abhigyanpatwari/GitNexus · error

File not found

Error message

File not found

What it means

HTTP 404 from the repo file-read API when fs.readFile throws ENOENT after the request passed validation and traversal containment — the path was well-formed and inside the repo, but no such file exists on disk. The handler distinguishes err.code === 'ENOENT' from other failures, which fall through to statusFromError (400/403/500). Note the API reads the real filesystem, not the index, so a file present in stale index results but deleted from the working tree will still 404.

Solutions

  1. Verify the file exists in the working tree of the served repository (git status / ls) at the exact case
  2. Re-run gitnexus analyze or re-fetch search results so the UI's paths match the current tree
  3. Check you are querying the right repository (?repo= matches the repo containing the file)
  4. Handle 404 gracefully in the UI by invalidating cached result entries that reference the missing path

Example fix

// before
const res = await fetch(`${base}/api/file?path=${hit.path}`);
const body = await res.json(); // { error: 'File not found' } breaks the viewer

// after
const res = await fetch(`${base}/api/file?path=${encodeURIComponent(hit.path)}`);
if (res.status === 404) { removeFromResults(hit); notifyUser('File no longer exists — results refreshed'); return; }
Defensive patterns

Strategy: validation

Validate before calling

// Only request files that the current results/tree actually reference.
if (!tree.has(filePath)) {
  await refreshIndex(); // re-fetch grep/query results or re-run analyze
  if (!tree.has(filePath)) throw new Error(`file not in current tree: ${filePath}`);
}

Try / catch

const res = await fetch(fileUrl);
if (res.status === 404 && (await res.json()).error === 'File not found') {
  dropStaleResult(filePath); // invalidate cached references instead of crashing the viewer
  return null;
}

Prevention

When it happens

Trigger: Requesting a file deleted or renamed since it was indexed; a case mismatch on case-sensitive filesystems (README.md vs readme.md); pointing at the wrong repo (?repo=) where the relative path does not exist; requesting a path that only exists on another branch.

Common situations: Web UI holding stale grep/query results after a branch switch or rebase; files generated at index time but later cleaned (build artifacts); developers testing with paths from their laptop on a CI checkout that differs; typo in the filename.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20). Data as JSON: /api/errors/49f0ac4af33dd8ce. Report an issue: GitHub.

Appendix: source

Thrown at gitnexus/src/server/api.ts:802

    if (startLine !== undefined && Number.isFinite(startLine)) {
      const lines = raw.split('\n');
      const start = Math.max(0, startLine);
      const end =
        endLine !== undefined && Number.isFinite(endLine)
          ? Math.min(lines.length, endLine + 1)
          : lines.length;
      res.json({
        content: lines.slice(start, end).join('\n'),
        startLine: start,
        endLine: end - 1,
        totalLines: lines.length,
      });
    } else {
      res.json({ content: raw, totalLines: raw.split('\n').length });
    }
  } catch (err: any) {
    if (err.code === 'ENOENT') {
      res.status(404).json({ error: 'File not found' });
    } else {
      // statusFromError returns err.status for BadRequestError / ForbiddenError
      // (assertString → 400 on array-form ?path=a&path=b; ForbiddenError → 403
      // on traversal). Falls back to 500 for unrecognized failures.
      res.status(statusFromError(err)).json({ error: err.message || 'Failed to read file' });
    }
  }
};

async function loadFtsSession(storagePath: string): Promise<{
  meta: Awaited<ReturnType<typeof loadMeta>>;
  ftsDisabledReason: FtsDisabledReason | undefined;
  skipFts?: true;
}> {
  const meta = await loadMeta(storagePath);
  const ftsDisabledReason = getFtsDisabledReason(meta?.capabilities?.fts);
  return {
    meta,

View on GitHub (pinned to ac9a4e9abd)