abhigyanpatwari/GitNexus · error · StorageDeletionError
err.message
Error message
err.message
What it means
This is a 400 response from the DELETE repository endpoint. Before deleting a repo's index storage, the server calls requireDeletableStoragePath, which throws StorageDeletionError when the path is not a registered, deletable GitNexus storage directory. The server refuses to delete and returns the validator's message to the client.
Solutions
- Check the error message body for the specific path problem and verify the repo entry's storagePath exists and looks like a GitNexus index directory
- Confirm GITNEXUS_STORAGE_PATH / GITNEXUS_STORAGE_ROOT env vars match where the index was actually created
- Run `gitnexus status` (or re-run `gitnexus analyze`) to re-register the storage directory, then retry the delete
- If the path is safe but unregistered, remove it manually with rm after confirming it contains no data you need
Example fix
// before: deleting a repo whose storage dir was moved
await fetch(`/api/repos/${name}`, { method: 'DELETE' });
// 400 { error: 'Unsafe index storage path ...' }
// after: re-register storage first
cd my-repo && gitnexus analyze --index-only
await fetch(`/api/repos/${name}`, { method: 'DELETE' }); // 200 Defensive patterns
Strategy: try-catch
Validate before calling
const repo = await (await fetch('/api/repos')).json().then(rs => rs.find(r => r.name === name));
if (!repo || !repo.storagePath || !repo.sourceAvailable) throw new Error('no registered storage to delete'); Try / catch
const res = await fetch(`/api/repos/${name}`, { method: 'DELETE' });
if (res.status === 400) {
const { error } = await res.json();
console.error(`Deletion refused: ${error} — verify the repo's storage path is a registered GitNexus index`);
} Prevention
- Never move or delete a repo's .gitnexus directory manually; use CLI commands
- Keep GITNEXUS_STORAGE_PATH/GITNEXUS_STORAGE_ROOT consistent between indexing and server runs
- Re-run `gitnexus analyze --index-only` after restructuring a repo before deleting via API
When it happens
Trigger: Calling DELETE /api/repos/:name (the repo deletion route) when the repo's .gitnexus storage path fails the deletability check — e.g. the resolved storage path is outside the configured storage root, the entry has no registered storage path, or the directory does not look like a GitNexus index.
Common situations: Developers hitting this usually deleted or moved the repo's .gitnexus directory manually, pointed GITNEXUS_STORAGE_PATH/GITNEXUS_STORAGE_ROOT at a non-standard location, or try to remove a repo whose storage was created by an older GitNexus version with an unrecognized layout.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Unsafe index storage path
- Refusing to delete storage
- Refusing to delete storage: the storage inspection state is
- Refusing to delete storage: the target is the repository…
- Unsafe storage path for
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/83b75ab0b0a5660f.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/server/api.ts:1225
// delete; tighten if abuse is observed.
app.delete('/api/repo', createRouteLimiter(), requireTrustedOrigin, async (req, res) => {
try {
const repoName = requestedRepo(req);
if (!repoName) {
res.status(400).json({ error: 'Missing repo name' });
return;
}
const entry = await resolveRepo(repoName, false, undefined, { validateStorage: false });
if (!entry) {
res.status(404).json({ error: 'Repository not found' });
return;
}
let storagePath: string;
try {
storagePath = await requireDeletableStoragePath(entry);
} catch (err: any) {
if (err instanceof StorageDeletionError) {
res.status(400).json({ error: err.message });
return;
}
res.status(400).json({ error: err.message || 'Unsafe index storage path' });
return;
}
// Acquire repo lock — prevents deleting while analyze/embed is in flight
const lockKey = storagePath;
const lockErr = acquireRepoLock(lockKey);
if (lockErr) {
res.status(409).json({ error: lockErr });
return;
}
try {
// Close any open LadybugDB handle before deleting files
try {
await closeLbug();View on GitHub (pinned to ac9a4e9abd)