{"record":{"id":"b7bb698cfc2d5282","repo":"can1357/oh-my-pi","slug":"message-unable-to-read-sectionpath","errorCode":null,"errorMessage":"${message} || Unable to read ${sectionPath}","messagePattern":"(.+?) \\|\\| Unable to read (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/hashline/diff.ts","lineNumber":70,"sourceCode":"\t * authoring input; the final apply path still validates through Patcher.\n\t */\n\tskipHashValidation?: boolean;\n\t/**\n\t * Clipboard register shared across the sections of one patch preview.\n\t * `CUT` in an earlier section feeds a register-backed `PUT` in a later one,\n\t * so the preview matches apply. Multi-section previews MUST thread one\n\t * register through sections in patch order; omitted, each section gets a\n\t * private register (same-file cut/put still previews correctly).\n\t */\n\tclipboard?: Clipboard;\n}\n\nasync function readSectionText(absolutePath: string, sectionPath: string): Promise<string> {\n\ttry {\n\t\treturn await readEditFileText(absolutePath, sectionPath);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(message || `Unable to read ${sectionPath}`);\n\t}\n}\n\n/**\n * Streaming previews recompute on every streamed chunk; re-reading the target\n * file from disk each tick dominates the cost on large files. Cache the raw\n * section text keyed by mtime+size so any on-disk change invalidates\n * naturally. Used by the streaming path only — the args-complete pass always\n * reads fresh.\n */\nconst streamingTextCache = new Map<string, { mtimeMs: number; size: number; rawContent: string }>();\nconst STREAMING_TEXT_CACHE_MAX = 8;\n\nasync function readSectionTextCached(absolutePath: string, sectionPath: string): Promise<string> {\n\tlet stamp: { mtimeMs: number; size: number } | undefined;\n\ttry {\n\t\tconst stat = await Bun.file(absolutePath).stat();\n\t\tstamp = { mtimeMs: stat.mtimeMs, size: stat.size };","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/hashline/diff.ts#L52-L88","documentation":"readSectionText() wraps readEditFileText() for hashline section reads and rethrows any failure as a single Error whose message is the original error message, or a generic 'Unable to read <sectionPath>' fallback if the underlying error carried no message. The sectionPath here is the hashline header's file path (may include the snapshot tag), so most real failures propagate the underlying message (missing file, generated-file refusal) verbatim.","triggerScenarios":"Applying a hashline edit whose section header references a file that does not exist, is unreadable (permissions), was deleted between read and edit, or whose path is malformed — any readEditFileText failure inside the edit-apply path.","commonSituations":"Stale absolute/relative path after a rename, typos in the section header path, editing a file already deleted in the working tree, or an LLM hallucinating a path not present in its read output.","solutions":["Re-read the target with the read tool to get the current correct path and snapshot tag, then re-issue the edit.","Verify the file exists on disk at the path in the header (ls / stat).","Check the error message prefix above the '|| Unable to read' fallback for the real cause (ENOENT vs permissions vs generated-file refusal)."],"exampleFix":"// before\nhashlineEdit({ section: `@@@ src/oldName.ts:tag\\n- old line` });\n// after\n// after rename, re-read to get fresh path+tag:\nhashlineEdit({ section: `@@@ src/newName.ts:a1b2\\n- old line` });","handlingStrategy":"try-catch","validationCode":"const stat = await Bun.file(sectionPath.replace(/:[0-9a-f]+$/, '')).exists();\nif (!stat) throw new Error(`Section path does not exist: ${sectionPath}`);","typeGuard":null,"tryCatchPattern":"try {\n  const raw = await readSectionText(absPath, sectionPath);\n  return applyEdits(raw);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (msg.includes('Unable to read') || msg.includes('File not found')) {\n    return reReadAndReauthorEdit(sectionPath);\n  }\n  throw e;\n}","preventionTips":["Copy section paths verbatim from read/search output — never retype them.","Refresh path + snapshot tag after any rename/checkout.","Parse the message before the '|| Unable to read' separator to get the root cause."],"tags":["file-not-found","io","edit-tool","hashline"],"backgroundTag":"file-read-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}