The logic in OfflineData<dim, Number>::construct_boundary_map currently reads as follows:
for (auto cell = begin; cell != end; ++cell) {
if (!cell->is_artificial() /* !cell->is_artificial_on_level() /*)
continue;
for (auto f : GeometryInfo<dim>::face_indices()) {
const auto face = cell->face(f);
const auto id = face->boundary_id();
if (!face->at_boundary())
continue;
// ...
/* Skip nonlocal degrees of freedom: */
if (index >= n_locally_owned_)
continue;
} /* f */
} /* cell */
This logic only works in 2D and will fail in 3D when we encounter hanging nodes on boundaries. We might also miss to set up boundary degrees of freedom.