abhigyanpatwari/GitNexus · error · Error

Refusing to adopt branch metadata: storage is not owned by…

Error message

Refusing to adopt branch metadata: storage is not owned by this repository (${inspection.state}).

What it means

When an explicit storagePath is provided for branch-metadata adoption, inspectStoragePath is run and must report state 'owned' — i.e. the directory's metadata identifies this repository as owner. Any other state (unowned, owned-by-another-repo, corrupt, empty) aborts the adoption, preventing a branch index from being attached to storage that belongs to someone else or has no valid ownership receipt.

Solutions

  1. Run `gitnexus analyze` with that storagePath for this repository first so the ownership metadata exists.
  2. Inspect the metadata file under the storage directory and correct the repoPath/ownership recorded there.
  3. Choose the storage directory this repository actually owns (default .gitnexus or its external slot).
  4. Ensure no two repositories share the same GITNEXUS_STORAGE_PATH slot.

Example fix

// before
await adoptBranch(repo, branch, { storagePath: "/shared/other-repo-slot" });
// after
await analyze({ repo, storagePath: "/repos/repo/.gitnexus" });
await adoptBranch(repo, branch, { storagePath: "/repos/repo/.gitnexus" });
Defensive patterns

Strategy: validation

Validate before calling

const meta = JSON.parse(await readFile(path.join(storagePath, "index-meta.json"), "utf8"));
if (path.resolve(meta.repoPath) !== path.resolve(repoPath)) {
  throw new Error(`storage not owned by ${repoPath} (owned by ${meta.repoPath})`);
}

Try / catch

try {
  await adoptBranchMetadata(repo, branch, { storagePath });
} catch (err) {
  if (/storage is not owned by this repository/.test(String(err)) && /\((.+)\)/.test(String(err))) {
    const state = err.message.match(/\((.+)\)/)[1];
    if (state === "unowned" || state === "missing") await analyze({ repo, storagePath });
  } else throw err;
}

Prevention

When it happens

Trigger: registerRepo branch adoption with resolvedStoragePath defined while inspectStoragePath(storagePath, resolved) returns a state other than 'owned' — e.g. the directory was never analyzed, its metadata names a different repo, or the metadata is missing/corrupt.

Common situations: Pointing branch adoption at an external directory another project owns; the external slot was wiped or its metadata deleted; two repos misconfigured with the same GITNEXUS_STORAGE_PATH slot.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15). Data as JSON: /api/errors/ddc4c2d0b60353b3. Report an issue: GitHub.

Appendix: source

Thrown at gitnexus/src/storage/repo-manager.ts:1261

  const initialEntries = await readRegistry();
  const initialIdx = isRegistered(initialEntries);
  if (initialIdx < 0) return; // no-op, disk included (no self-heal)

  const resolved = path.resolve(repoPath);
  const storagePath =
    resolvedStoragePath === undefined
      ? getStoragePaths(resolved).storagePath
      : validateConfiguredStoragePath(resolvedStoragePath);
  const registeredStoragePath = initialEntries[initialIdx].storagePath;
  if (!registryPathEquals(canonicalizePath(registeredStoragePath), canonicalizePath(storagePath))) {
    throw new Error(
      `Refusing to adopt branch metadata: the registry storage path does not match the selected storage directory.`,
    );
  }
  if (resolvedStoragePath !== undefined) {
    const inspection = await inspectStoragePath(storagePath, resolved);
    if (inspection.state !== 'owned') {
      throw new Error(
        `Refusing to adopt branch metadata: storage is not owned by this repository (${inspection.state}).`,
      );
    }
  }
  // Remove a shadowed sub-index directory, mirroring `clean --branch`'s
  // containment guard: the target MUST live under .gitnexus/branches/.
  const branchesRoot = path.join(storagePath, BRANCHES_DIR);
  const branchDir = path.join(branchesRoot, branchSlug(branch));
  const branchRelativePath = path.relative(branchesRoot, branchDir);
  const branchDirIsContained =
    branchRelativePath !== '' &&
    branchRelativePath !== '..' &&
    !branchRelativePath.startsWith(`..${path.sep}`) &&
    !path.isAbsolute(branchRelativePath);
  let dirGone = false;
  if (branchDirIsContained) {
    let rmError: NodeJS.ErrnoException | undefined;
    await fs.rm(branchDir, { recursive: true, force: true }).catch((err: unknown) => {

View on GitHub (pinned to ac9a4e9abd)