abhigyanpatwari/GitNexus · error
Failed to read file
Error message
Failed to read file
What it means
A 500 response from the file-read endpoint (GET /api/file). If the requested file cannot be read and the error is not a storage-requirement error (which maps to 410), the handler returns err.message or the fallback 'Failed to read file'.
Solutions
- Verify the requested path exists in the repo working tree and is relative to the repo root
- Re-run `gitnexus analyze` to refresh the index if the working tree changed since indexing
- Check file permissions on the file for the server process user
- If the response is 410 (not this 500), the index uses non-full content retention — re-analyze or use local file access
Example fix
// before: requesting a file that moved
fetch('/api/file?path=src/old-name.ts') // 500 Failed to read file
// after: refresh index / use the current path
cd my-repo && gitnexus analyze
fetch('/api/file?path=src/new-name.ts') // 200 Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'fs';
const p = path.resolve(repoRoot, relPath);
if (!p.startsWith(path.resolve(repoRoot) + path.sep) || !existsSync(p)) throw new Error('bad file path'); Try / catch
const res = await fetch(`/api/file?path=${encodeURIComponent(p)}`);
if (res.status === 500) {
const { error } = await res.json();
console.warn('File read failed:', error); // re-index or fix the path
} Prevention
- Use repo-relative paths exactly as returned by search results
- Re-run `gitnexus analyze` whenever the working tree changes (renames/deletes)
- Handle 410 separately: it means content retention is off, not a read failure
When it happens
Trigger: GET /api/file?path=... where handleFileRequest throws: the path resolves outside the repo (traversal guard), the file was deleted after indexing, or a filesystem error occurs during readFile.
Common situations: Common when the working tree changed since indexing (file renamed/removed), the requested path uses wrong relative form, or the repo checkout moved on disk.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to list repos
- "path" must be an absolute path
- Upload failed
- -32000
- Analyzer build changed while its identity was being computed
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-09-15).
Data as JSON: /api/errors/7adafa330e840c99.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/server/api.ts:1578
} catch (err: any) {
if (sendStorageRequirementHttp(err, res)) return;
res.status(500).json(httpErrorBody(err, 'Search failed'));
}
});
// Read file — with path traversal guard
// Rate-limited (CodeQL js/missing-rate-limiting): per-request fs.readFile.
app.get('/api/file', createRouteLimiter(), async (req, res) => {
try {
const entry = await resolveRepo(requestedRepo(req));
if (!entry) {
res.status(404).json({ error: 'Repository not found' });
return;
}
await handleFileRequest(req, res, entry.path, await getSourceAvailability(entry));
} catch (err: any) {
if (sendStorageRequirementHttp(err, res)) return;
res.status(500).json({ error: err.message || 'Failed to read file' });
}
});
// Grep — regex search across file contents in the indexed repo
// Uses filesystem-based search for memory efficiency (never loads all files into memory)
// Rate-limited (CodeQL js/missing-rate-limiting): scans every file in
// the indexed repo per request — heaviest I/O endpoint. Same default 60
// rpm/IP for now; consider tightening if real-world load shows abuse.
app.get('/api/grep', createRouteLimiter(), async (req, res) => {
try {
const entry = await resolveRepo(requestedRepo(req));
if (!entry) {
res.status(404).json({ error: 'Repository not found' });
return;
}
const sourceAvailability = await getSourceAvailability(entry);
if (!sourceAvailability.available) {
sendSourceUnavailable(res, sourceAvailability);View on GitHub (pinned to ac9a4e9abd)