abhigyanpatwari/GitNexus · error · StorageDeletionError
Refusing to delete storage: the storage inspection state is
Error message
Refusing to delete storage: the storage inspection state is "${inspection.state}" What it means
A StorageDeletionError thrown when the pre-deletion inspection yields a state outside the allowed set: for a locally-owned .gitnexus the allowed states are missing/empty/unowned/owned/foreign, while an external storage slot may only be deleted when its state is 'owned'. Any other state (e.g. an external slot that is 'foreign' or 'unowned' relative to this repo) aborts the delete.
Solutions
- Delete the storage from the repository that actually owns it (run the delete where the slot is 'owned').
- Unset GITNEXUS_STORAGE_PATH to use the repo's own .gitnexus, whose states are all deletable.
- Re-register or re-point the external slot at the correct repoPath, then retry.
- Manually remove the foreign external slot directory after confirming ownership outside the tool.
Example fix
// before (external slot owned by another checkout) GITNEXUS_STORAGE_PATH=/data/slots/repo-a npx gitnexus clean repo-b // after (use repo-b's own storage) unset GITNEXUS_STORAGE_PATH && npx gitnexus clean repo-b
Defensive patterns
Strategy: try-catch
Validate before calling
const inspection = await inspectStoragePath(storagePath);
const isLocal = isRepositoryLocalStoragePath(repoPath, storagePath);
const allowed = isLocal ? ['missing','empty','unowned','owned','foreign'] : ['owned'];
if (!allowed.includes(inspection.state)) {
console.error(`External slot state is ${inspection.state}; delete from the owning repo instead`);
} Type guard
const isDeletable = (i: StorageInspection, isLocal: boolean): boolean => isLocal ? true : i.state === 'owned';
Try / catch
try {
await deleteRepoStorage(repoName);
} catch (err) {
if (err instanceof StorageDeletionError && err.inspection) {
console.error(`Storage state ${err.inspection.state} not deletable here; run from the owning checkout`);
} else throw err;
} Prevention
- Perform deletions from the checkout that owns the external storage slot.
- Prefer the default per-repo .gitnexus storage to avoid cross-checkout ownership issues.
- Verify slot ownership (state === 'owned') before external-slot cleanup.
- After moving a repo, re-register it so slot ownership matches the new path.
When it happens
Trigger: Deleting a repo whose storage is an external slot (GITNEXUS_STORAGE_PATH-style) that inspection classifies as not owned by this repository; deleting through a storage path pointing at another repo's index.
Common situations: Two checkouts sharing one external index directory and the second one attempting cleanup; a moved repository whose external slot is registered under the original repoPath; typos in GITNEXUS_STORAGE_PATH selecting a foreign 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
- Refusing to delete storage: the target is the repository…
- err.message
- Refusing to adopt branch metadata: storage is not owned by…
- Refusing to delete storage
- Storage requirement not met: foreign external slot is not…
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/c17c291a6b01a194.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/storage/storage-resolver.ts:717
isPathAncestor(comparableStorage, comparableRepo)
) {
throw new StorageDeletionError(
expectedStoragePath,
actualStoragePath,
undefined,
'the target is the repository, one of its parents, or a filesystem root',
);
}
const inspection = await inspectRegisteredStorage({
path: repoPath,
storagePath: actualStoragePath,
});
const allowedStates: readonly StorageState[] = storageIsLocal
? ['missing', 'empty', 'unowned', 'owned', 'foreign']
: ['owned'];
if (!allowedStates.includes(inspection.state)) {
throw new StorageDeletionError(
expectedStoragePath,
actualStoragePath,
inspection,
`the storage inspection state is "${inspection.state}"`,
);
}
return actualStoragePath;
};
/** Ensure a selected index directory is usable before an analysis takes its lock. */
export const ensureStoragePathWritable = async (storagePath: string): Promise<void> => {
const resolved = validateConfiguredStoragePath(storagePath);
await fsp.mkdir(resolved, { recursive: true });
const stat = await fsp.stat(resolved);
if (!stat.isDirectory()) {
throw new InvalidStoragePathError(`Index storage path is not a directory: ${resolved}`);
}
await fsp.access(resolved, fs.constants.R_OK | fs.constants.W_OK);View on GitHub (pinned to ac9a4e9abd)