Budibase/budibase · error · HTTPError

Project package contains docs that are not reachable from th

Error message

Project package contains docs that are not reachable from the root project.

What it means

After shape and presence checks, the importer walks the dependency graph starting from rootProjectId (imports.ts:774-796) following each resource's dependencies (only into ids present in resources). Any doc present in the package whose id is not reachable from the root is rejected with 400 — the package would import orphan resources with no connection to the project.

Source

Thrown at packages/server/src/sdk/workspace/projects/backups/imports.ts:791

  const reachable = new Set<string>()
  const visit = (id: string) => {
    if (reachable.has(id)) {
      return
    }
    reachable.add(id)
    for (const dependency of dependencyIndex.resources[id]?.dependencies ||
      []) {
      if (dependencyIndex.resources[dependency.id]) {
        visit(dependency.id)
      }
    }
  }
  visit(dependencyIndex.rootProjectId)

  for (const docId of actualDocIds) {
    if (!reachable.has(docId)) {
      throw new HTTPError(
        "Project package contains docs that are not reachable from the root project.",
        400
      )
    }
  }

  if (
    dependencyIndex.directMembers.some(member => !actualDocIds.has(member.id))
  ) {
    throw new HTTPError(
      "Project package docs do not match dependency-index.json.",
      400
    )
  }

  const countedResources = docs.reduce<Partial<Record<ResourceType, number>>>(
    (acc, doc) => {
      acc[doc.resourceType] = (acc[doc.resourceType] || 0) + 1

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Add dependency edges so every resource is reachable from rootProjectId's dependency graph (transitively).
  2. Regenerate the package with the official exporter, which builds the graph from the live project.
  3. Remove genuinely orphaned resources (docs + index entries) from the package.
  4. Trace reachability manually: start at resources[rootProjectId].dependencies and confirm every key appears in the transitive closure.

Example fix

// before: ta_orphan not referenced anywhere
// after: reference it from the root or its parent
"app_abc": { "dependencies": [{ "id": "ta_orphan", "name": "Orphan", "type": "table" }] }
Defensive patterns

Strategy: validation

Validate before calling

const reachable = new Set([pkg.dependencyIndex.rootProjectId])
let grew = true
while (grew) {
  grew = false
  for (const [id, r] of Object.entries(pkg.dependencyIndex.resources)) {
    if (reachable.has(id)) continue
    if ((r.dependencies || []).some(d => reachable.has(d.id))) {
      reachable.add(id); grew = true
    }
  }
}
const orphans = pkg.docs.filter(d => !reachable.has(d._id))
if (orphans.length) throw new Error(`Unreachable docs: ${orphans.map(d => d._id).join(", ")}`)

Try / catch

try {
  await importProjectPackage(file)
} catch (e) {
  if (e.status === 400 && e.message.includes("not reachable from the root project")) {
    // find the disconnected subgraph and link it or remove it
  } else throw e
}

Prevention

When it happens

Trigger: Importing a package containing docs that exist in resources and in the docs set, but are not referenced (directly or transitively) by the root project's dependency chain — e.g. disconnected subgraphs, a resource linked only from another orphan, or dependencies arrays that omit references.

Common situations: Hand-assembled packages where resources were added to the index but never linked from the root's dependency tree; editing dependencies arrays and dropping an edge; merging two exports so one tree hangs unattached.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/8619aff6da35a99e. Report an issue: GitHub.