{"record":{"id":"d3d864a3a27be97d","repo":"paperclipai/paperclip","slug":"acpx-provider-dependency-ancestry-exceeds-its-boun","errorCode":null,"errorMessage":"ACPX provider dependency ancestry exceeds its bound","messagePattern":"ACPX provider dependency ancestry exceeds its bound","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/acpx/installation-integrity.ts","lineNumber":685,"sourceCode":"  }\n  for (const supplemental of supplementalPackages) {\n    if (\n      supplemental.directory !== commandDirectory &&\n      !dependencyAncestors.some(\n        (ancestor) => ancestor.path === supplemental.directory,\n      )\n    ) {\n      dependencyAncestors.push(\n        await inspectExplicitDependencyRoot(\n          supplemental.directory,\n          `${profile.agent} dependency`,\n        ),\n      );\n      dependencyAncestorFormats.push(supplemental.format);\n    }\n  }\n  if (dependencyAncestors.length > MAX_DEPENDENCY_ANCESTORS) {\n    throw new Error(\"ACPX provider dependency ancestry exceeds its bound\");\n  }\n  const serverDependencyAncestorCount = serverDependencyAncestors.length;\n\n  const commandDigest = command.digest;\n  const commandIdentity = command.identity;\n  return Object.freeze({\n    commandDigest,\n    agentServerPackageJsonPath: serverPackageJsonPath,\n    agentRuntimePackageJsonPath: runtimePackageJsonPath,\n    async openCommand(): Promise<VerifiedAcpxCommandLease> {\n      const currentDirectory = await openVerifiedCommandDirectory(\n        commandDirectory,\n        \"provider\",\n      );\n      if (\n        !sameDirectoryIdentity(\n          currentDirectory.identity,\n          commandDirectoryIdentity,","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/acpx/installation-integrity.ts#L667-L703","documentation":"The verifier builds a bounded list of dependency-ancestor directories (server ancestors, the runtime package directory, and each supplemental claude dependency) that must be opened and monitored for the launch. MAX_DEPENDENCY_ANCESTORS caps this list; exceeding it would mean unbounded trust roots, so verification fails instead of opening an arbitrary number of directories.","triggerScenarios":"verifyQualifiedAcpxInstallation where, after pushing the runtime directory and every distinct supplemental claude dependency directory not already covered by serverDependencyAncestors or commandDirectory, dependencyAncestors.length exceeds MAX_DEPENDENCY_ANCESTORS — i.e. many supplemental dependencies resolve to distinct directories outside the normal ancestor chain.","commonSituations":"Deeply nested or unusual install layouts (pnpm symlink farms resolving supplemental packages to many distinct realpaths); a qualified profile expecting a flat node_modules but installed into an isolated per-package layout; qualification-time layout differing from the deployment layout so supplemental dirs no longer coincide with server ancestors.","solutions":["Reinstall with a standard hoisted layout (npm ci or pnpm with hoisting) so supplemental dependency directories coincide with the server package's ancestors.","Re-run qualification in the same install layout used at runtime so the ancestor count stays within the bound.","Increase MAX_DEPENDENCY_ANCESTORS deliberately if the qualified set legitimately needs more roots, and re-verify (treat as a code change, not a workaround).","Check realpath output for each dependency: excessive distinct realpaths usually indicate duplicated installs; dedupe node_modules."],"exampleFix":"// before (isolated layout, each dep its own root)\n$ pnpm install --node-linker=isolated\n// after\n$ pnpm install --node-linker=hoisted  # or npm ci, collapsing supplemental dirs into the ancestor chain","handlingStrategy":"validation","validationCode":"// count distinct supplemental roots before verification\nconst roots = new Set([commandDirectory, ...supplementalDirs]);\nif (roots.size > MAX_DEPENDENCY_ANCESTORS) {\n  throw new Error(`install layout yields ${roots.size} ancestor roots; expected <= ${MAX_DEPENDENCY_ANCESTORS}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await verifyQualifiedAcpxInstallation(input);\n} catch (e) {\n  if (e.message === \"ACPX provider dependency ancestry exceeds its bound\") {\n    execSync(\"pnpm install --node-linker=hoisted\"); // collapse to standard layout, then re-verify\n  } else throw e;\n}","preventionTips":["Use the same install layout (hoisted npm/pnpm) at runtime as during qualification.","Avoid isolated/symlink-farm node-linkers for the ACPX install tree.","Dedupe dependencies so supplemental packages resolve into existing ancestor directories."],"tags":["installation-integrity","acpx","dependency-ancestry","limit-exceeded"],"backgroundTag":"value-out-of-range","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}