{"record":{"id":"83b75ab0b0a5660f","repo":"abhigyanpatwari/GitNexus","slug":"err-message","errorCode":null,"errorMessage":"err.message","messagePattern":"err\\.message","errorType":"http","errorClass":"StorageDeletionError","httpStatus":400,"severity":"error","filePath":"gitnexus/src/server/api.ts","lineNumber":1225,"sourceCode":"  // delete; tighten if abuse is observed.\n  app.delete('/api/repo', createRouteLimiter(), requireTrustedOrigin, async (req, res) => {\n    try {\n      const repoName = requestedRepo(req);\n      if (!repoName) {\n        res.status(400).json({ error: 'Missing repo name' });\n        return;\n      }\n      const entry = await resolveRepo(repoName, false, undefined, { validateStorage: false });\n      if (!entry) {\n        res.status(404).json({ error: 'Repository not found' });\n        return;\n      }\n      let storagePath: string;\n      try {\n        storagePath = await requireDeletableStoragePath(entry);\n      } catch (err: any) {\n        if (err instanceof StorageDeletionError) {\n          res.status(400).json({ error: err.message });\n          return;\n        }\n        res.status(400).json({ error: err.message || 'Unsafe index storage path' });\n        return;\n      }\n\n      // Acquire repo lock — prevents deleting while analyze/embed is in flight\n      const lockKey = storagePath;\n      const lockErr = acquireRepoLock(lockKey);\n      if (lockErr) {\n        res.status(409).json({ error: lockErr });\n        return;\n      }\n\n      try {\n        // Close any open LadybugDB handle before deleting files\n        try {\n          await closeLbug();","sourceCodeStart":1207,"sourceCodeEnd":1243,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/server/api.ts#L1207-L1243","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: deleting a repo whose storage dir was moved\nawait fetch(`/api/repos/${name}`, { method: 'DELETE' });\n// 400 { error: 'Unsafe index storage path ...' }\n\n// after: re-register storage first\ncd my-repo && gitnexus analyze --index-only\nawait fetch(`/api/repos/${name}`, { method: 'DELETE' }); // 200","handlingStrategy":"try-catch","validationCode":"const repo = await (await fetch('/api/repos')).json().then(rs => rs.find(r => r.name === name));\nif (!repo || !repo.storagePath || !repo.sourceAvailable) throw new Error('no registered storage to delete');","typeGuard":null,"tryCatchPattern":"const res = await fetch(`/api/repos/${name}`, { method: 'DELETE' });\nif (res.status === 400) {\n  const { error } = await res.json();\n  console.error(`Deletion refused: ${error} — verify the repo's storage path is a registered GitNexus index`);\n}","preventionTips":["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"],"tags":["http-400","storage","deletion","path-validation"],"backgroundTag":"path-traversal-blocked","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"}