abhigyanpatwari/GitNexus · error · Error
Refusing to register
Error message
Refusing to register ${resolved}: external storage metadata must bind storagePath to the selected directory. What it means
When an explicit (external) storagePath is selected, registerRepo requires the metadata receipt to bind storagePath to that directory. If meta.storagePath is absent and the storage directory is not the repo's default .gitnexus location, the write is refused — otherwise the registry would claim external storage while the metadata records none, breaking later lookups.
Solutions
- Re-run analysis so metadata is written into the selected external storage directory with storagePath recorded.
- Point opts.storagePath at the directory the metadata actually names (or the repo's default .gitnexus).
- Clear the stale metadata in the external directory and re-analyze.
- Keep GITNEXUS_STORAGE_PATH consistent between the analyze and register invocations.
Example fix
// before
await registerRepo(repo, { storagePath: "/external/slot" }); // meta.storagePath undefined
// after
await analyze({ storagePath: "/external/slot" }); // regenerate meta there
await registerRepo(repo, { storagePath: "/external/slot" }); Defensive patterns
Strategy: validation
Validate before calling
const meta = JSON.parse(await readFile(path.join(storagePath, "index-meta.json"), "utf8"));
const isDefault = path.resolve(storagePath) === path.resolve(repoPath, ".gitnexus");
if (!isDefault && (meta.storagePath === undefined || path.resolve(meta.storagePath) !== path.resolve(storagePath))) {
throw new Error("metadata not bound to selected external storage");
} Try / catch
try {
await registerRepo(repoPath, { storagePath });
} catch (err) {
if (/external storage metadata must bind storagePath/.test(String(err))) {
await analyze({ repoPath, storagePath }); // regenerate metadata bound to the slot
await registerRepo(repoPath, { storagePath });
} else throw err;
} Prevention
- Run analyze and register with identical storage options in the same environment.
- Don't move metadata produced under default storage into external slots.
- Use a wrapper script exporting the same GITNEXUS_STORAGE_PATH for all gitnexus invocations.
When it happens
Trigger: Calling registerRepo with opts.storagePath set to a non-default directory while the metadata file in that directory has no storagePath field (e.g. metadata created by a default-location analyze).
Common situations: Analyze first ran with default storage (.gitnexus in-repo), then registration is attempted with GITNEXUS_STORAGE_PATH or an explicit storagePath pointing elsewhere; metadata was copied from a default-storage repo into an external slot.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Analysis not finalized: missing registry-entry for
- Refusing to register
- Refusing to register
- Refusing to adopt branch metadata: the registry storage…
- Analysis did not finalize for
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/21bcf986c716ce0b.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/storage/repo-manager.ts:995
// Production write paths pass the storage slot they already validated. Do
// not let a changed environment/registry redirect their registry entry, and
// require the metadata receipt to describe that same repository and slot.
// The omitted-option path deliberately retains legacy direct-call behavior.
if (opts?.storagePath !== undefined) {
if (!registryPathEquals(canonicalizePath(meta.repoPath), canonicalInput)) {
throw new Error(
`Refusing to register ${resolved}: metadata belongs to ${meta.repoPath}, not this repository.`,
);
}
if (
meta.storagePath === undefined &&
!registryPathEquals(
canonicalizePath(storagePath),
canonicalizePath(defaultStoragePath(resolved)),
)
) {
throw new Error(
`Refusing to register ${resolved}: external storage metadata must bind storagePath to the selected directory.`,
);
}
if (
meta.storagePath !== undefined &&
!registryPathEquals(canonicalizePath(meta.storagePath), canonicalizePath(storagePath))
) {
throw new Error(
`Refusing to register ${resolved}: metadata storagePath does not match the selected storage directory.`,
);
}
}
// Mutating writes must not treat an unreadable/truncated registry as empty
// (#3094): lenient `readRegistry()` returns `[]` on parse failure and would
// replace the machine-wide file with only this entry. ENOENT stays empty.
const entries = await readRegistryStrict();
const existingIdx = entries.findIndex((e) => {View on GitHub (pinned to ac9a4e9abd)