{"record":{"id":"76d31f4b2a9e563f","repo":"abhigyanpatwari/GitNexus","slug":"unsafe-index-storage-path","errorCode":null,"errorMessage":"Unsafe index storage path","messagePattern":"Unsafe index storage path","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"gitnexus/src/server/api.ts","lineNumber":1228,"sourceCode":"      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();\n        } catch {}\n\n        // 1. Delete the .gitnexus index/storage directory","sourceCodeStart":1210,"sourceCodeEnd":1246,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/server/api.ts#L1210-L1246","documentation":"This is the fallback message of the same 400 response: when requireDeletableStoragePath throws a non-StorageDeletionError, the handler returns err.message or the literal 'Unsafe index storage path'. It means the repository's storage path could not be validated as safe to delete for a reason not covered by the dedicated error type.","triggerScenarios":"DELETE /api/repos/:name where the storage-path validation throws an unexpected error — missing entry.path, filesystem errors stat-ing the directory, or a path that fails the safety check in requireDeletableStoragePath without producing a StorageDeletionError.","commonSituations":"Seen when the repo directory was removed from disk but the registry entry remains, permissions on the storage directory prevent stat, or a custom GITNEXUS_STORAGE_PATH points outside the allowed root.","solutions":["Verify the repo's storage directory exists on disk and is readable by the server process","Check GITNEXUS_STORAGE_PATH / GITNEXUS_STORAGE_ROOT are set consistently with where the index lives","Re-run `gitnexus analyze --index-only` in the repo to rebuild/re-register a valid storage layout","Inspect the server logs for the underlying throw if err.message is empty"],"exampleFix":"// before: repo dir deleted, registry entry stale\nrm -rf my-repo && curl -X DELETE localhost:4747/api/repos/my-repo\n// 400 { error: 'Unsafe index storage path' }\n\n// after: remove the stale entry cleanly\n// restore or recreate the repo dir first, or edit the registry entry, then delete\ncurl -X DELETE localhost:4747/api/repos/my-repo // 200","handlingStrategy":"validation","validationCode":"import { existsSync } from 'fs';\nconst ok = existsSync(storagePath) && existsSync(`${storagePath}/index`); // adjust to known layout\nif (!ok) throw new Error('storage directory missing or unrecognized');","typeGuard":null,"tryCatchPattern":"if (res.status === 400 && (await res.text()).includes('Unsafe index storage path')) {\n  // storage layout/registration problem — refresh the index instead of deleting\n  await exec('gitnexus analyze --index-only');\n}","preventionTips":["Verify the repo entry's storagePath exists and is readable before issuing a delete","Avoid custom GITNEXUS_STORAGE_* paths unless the same value is used by every client","Check server permissions on the storage directory"],"tags":["http-400","storage","deletion","fallback"],"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"}