{"record":{"id":"401a312eda217680","repo":"can1357/oh-my-pi","slug":"file-not-found-relativepath","errorCode":null,"errorMessage":"File not found: ${relativePath}","messagePattern":"File not found: (.+?)","errorType":"exception","errorClass":"NotFoundError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/hashline/filesystem.ts","lineNumber":118,"sourceCode":"\t\t// snapshot tag uniquely names. Confine the redirect to locations a plain\n\t\t// \"write\" may legitimately target:\n\t\t//  1. the working tree (the model dropped the directory), or\n\t\t//  2. the session `local://` sandbox where plan/scratch artifacts live —\n\t\t//     the snapshot tag proves the model wrote/read that exact file this\n\t\t//     session, so a bare `plan.md#tag` should land on `local://plan.md`.\n\t\t// The secret vault and any other out-of-tree path stay refused.\n\t\tconst root = canonicalSnapshotKey(this.session.cwd);\n\t\tif (resolvedPath === root || resolvedPath.startsWith(`${root}${path.sep}`)) return true;\n\t\treturn targetsLocalSandbox(this.session, resolvedPath);\n\t}\n\n\tasync readText(relativePath: string): Promise<string> {\n\t\tconst absolutePath = this.resolveAbsolute(relativePath);\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = await readEditFileText(absolutePath, relativePath);\n\t\t} catch (error) {\n\t\t\tif (isEnoent(error)) throw new NotFoundError(relativePath, error);\n\t\t\tif (error instanceof Error && error.message === `File not found: ${relativePath}`) {\n\t\t\t\tthrow new NotFoundError(relativePath, error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\t// Refuse edits against generated files (lockfiles, models.json, …).\n\t\tassertEditableFileContent(content, relativePath, this.session.settings);\n\t\treturn content;\n\t}\n\n\toverride async readBinary(relativePath: string): Promise<Uint8Array | undefined> {\n\t\tconst absolutePath = this.resolveAbsolute(relativePath);\n\t\tif (isNotebookPath(absolutePath)) return undefined;\n\t\ttry {\n\t\t\treturn await fs.readFile(absolutePath);\n\t\t} catch (error) {\n\t\t\tif (isEnoent(error)) throw new NotFoundError(relativePath, error);\n\t\t\tthrow error;","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/hashline/filesystem.ts#L100-L136","documentation":"HashlineFilesystem.readText() resolves the relative path against the session cwd and reads via readEditFileText; ENOENT — and notably also a readEditFileText failure whose message is literally 'File not found: <path>' — is converted to a NotFoundError. This second branch exists because readEditFileText may throw its own 'File not found' Error for cases isEnoent misses (e.g. path inside a non-existent directory reported by the edit-file reader).","triggerScenarios":"Applying an edit or preview against a relativePath that does not exist under session.cwd: file deleted, wrong relative path, path never created, or edit issued against a file in a removed directory.","commonSituations":"Stale session state after a git checkout/rebase removed the file; model inventing a path not in its context; case-sensitivity mismatch (Foo.ts vs foo.ts) on Linux.","solutions":["Verify the file exists relative to the session cwd (ls) and correct the relative path.","Re-read the file listing / re-run read to refresh which files exist, then re-issue.","If the file should exist but was deleted, restore it or use the write tool to recreate it."],"exampleFix":"// before\nedit({ section: `@@@ src/helpers/removed.ts:a1b2\\n- x` });\n// after\n// file was deleted in rebase — target the new location\nedit({ section: `@@@ src/utils/helpers.ts:c3d4\\n- x\\n+ y` });","handlingStrategy":"try-catch","validationCode":"import * as path from 'node:path';\nconst abs = path.resolve(session.cwd, relativePath);\nif (!(await Bun.file(abs).exists())) {\n  throw new Error(`Refusing edit: ${relativePath} does not exist under ${session.cwd}`);\n}","typeGuard":null,"tryCatchPattern":"import { NotFoundError } from '.../filesystem';\ntry {\n  const text = await fs.readText(relativePath);\n  return applyEdit(text);\n} catch (e) {\n  if (e instanceof NotFoundError) {\n    return { status: 'missing-file', path: relativePath }; // skip or recreate via write\n  }\n  throw e;\n}","preventionTips":["Re-list files after git operations (checkout, rebase, clean) before editing.","Match file name case exactly — Linux is case-sensitive.","Check for broken symlinks when a path 'should' exist."],"tags":["file-not-found","enoent","hashline","edit-tool"],"backgroundTag":"file-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}