{"record":{"id":"9a04aa774d74902a","repo":"abhigyanpatwari/GitNexus","slug":"refusing-to-adopt-branch-metadata-the-registry-storage-path","errorCode":null,"errorMessage":"Refusing to adopt branch metadata: the registry storage path does not match the selected storage directory.","messagePattern":"Refusing to adopt branch metadata: the registry storage path does not match the selected storage directory\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/storage/repo-manager.ts","lineNumber":1254,"sourceCode":"  resolvedStoragePath?: string,\n): Promise<void> => {\n  const canonicalInput = canonicalizePath(repoPath);\n  const isRegistered = (list: RegistryEntry[]): number =>\n    list.findIndex((e) => registryPathEquals(canonicalizePath(e.path), canonicalInput));\n  // Cheap membership gate only (#2364 review F2): never touch the disk for an\n  // unregistered repo. The mutate below re-reads its own fresh snapshot.\n  const initialEntries = await readRegistry();\n  const initialIdx = isRegistered(initialEntries);\n  if (initialIdx < 0) return; // no-op, disk included (no self-heal)\n\n  const resolved = path.resolve(repoPath);\n  const storagePath =\n    resolvedStoragePath === undefined\n      ? getStoragePaths(resolved).storagePath\n      : validateConfiguredStoragePath(resolvedStoragePath);\n  const registeredStoragePath = initialEntries[initialIdx].storagePath;\n  if (!registryPathEquals(canonicalizePath(registeredStoragePath), canonicalizePath(storagePath))) {\n    throw new Error(\n      `Refusing to adopt branch metadata: the registry storage path does not match the selected storage directory.`,\n    );\n  }\n  if (resolvedStoragePath !== undefined) {\n    const inspection = await inspectStoragePath(storagePath, resolved);\n    if (inspection.state !== 'owned') {\n      throw new Error(\n        `Refusing to adopt branch metadata: storage is not owned by this repository (${inspection.state}).`,\n      );\n    }\n  }\n  // Remove a shadowed sub-index directory, mirroring `clean --branch`'s\n  // containment guard: the target MUST live under .gitnexus/branches/.\n  const branchesRoot = path.join(storagePath, BRANCHES_DIR);\n  const branchDir = path.join(branchesRoot, branchSlug(branch));\n  const branchRelativePath = path.relative(branchesRoot, branchDir);\n  const branchDirIsContained =\n    branchRelativePath !== '' &&","sourceCodeStart":1236,"sourceCodeEnd":1272,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/storage/repo-manager.ts#L1236-L1272","documentation":"When adopting branch metadata, the code validates that the registry entry's storagePath matches the storage directory selected for the branch adoption (either resolvedStoragePath or the repo's resolved storage path). A mismatch means the registry row points at a different storage slot, and adopting branch metadata there would attach the branch index to the wrong storage.","triggerScenarios":"registerRepo/branch-adoption path finds an existing registry entry (initialEntries[initialIdx]) whose storagePath differs from validateConfiguredStoragePath(resolvedStoragePath) or getStoragePaths(resolved).storagePath.","commonSituations":"Branch metadata adoption after GITNEXUS_STORAGE_PATH changed; the repo's registry entry was created under a default .gitnexus path but adoption now targets an external slot (or vice versa); registry rows copied between machines with different absolute paths.","solutions":["Invoke adoption with the same storagePath recorded in the registry entry.","Remove the stale registry entry (or re-register the repo) so adoption can recreate it against the selected storage directory.","Re-run analyze under the same storage configuration used at registration.","Unset/re-set GITNEXUS_STORAGE_PATH to match the original registration environment."],"exampleFix":"// before\nawait adoptBranch(repo, branch, { storagePath: \"/external/new-slot\" });\n// after\nawait adoptBranch(repo, branch, { storagePath: registryEntry.storagePath });","handlingStrategy":"validation","validationCode":"const entries = JSON.parse(await readFile(registryPath, \"utf8\"));\nconst entry = entries.find((e) => path.resolve(e.path) === path.resolve(repoPath));\nif (entry && path.resolve(entry.storagePath) !== path.resolve(selectedStoragePath)) {\n  throw new Error(`registry storagePath ${entry.storagePath} != selected ${selectedStoragePath}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await adoptBranchMetadata(repo, branch, { storagePath });\n} catch (err) {\n  if (/registry storage path does not match/.test(String(err))) {\n    // align storagePath with the registry entry or re-register, then retry\n  } else throw err;\n}","preventionTips":["Don't change GITNEXUS_STORAGE_PATH between registration and branch operations.","Re-register the repo when its storage slot changes.","Mirror the same storage configuration across machines/scripts operating on the same repo."],"tags":["registry","storage-path","branch","mismatch"],"backgroundTag":"conflicting-config-options","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-09-15T23:29:44.066Z","contentChangedAt":"2026-09-15T23:29:44.066Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}