can1357/oh-my-pi · error
${message} || Unable to read ${sectionPath}
Error message
${message} || Unable to read ${sectionPath} What it means
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.
Source
Thrown at packages/coding-agent/src/edit/hashline/diff.ts:70
* authoring input; the final apply path still validates through Patcher.
*/
skipHashValidation?: boolean;
/**
* Clipboard register shared across the sections of one patch preview.
* `CUT` in an earlier section feeds a register-backed `PUT` in a later one,
* so the preview matches apply. Multi-section previews MUST thread one
* register through sections in patch order; omitted, each section gets a
* private register (same-file cut/put still previews correctly).
*/
clipboard?: Clipboard;
}
async function readSectionText(absolutePath: string, sectionPath: string): Promise<string> {
try {
return await readEditFileText(absolutePath, sectionPath);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(message || `Unable to read ${sectionPath}`);
}
}
/**
* Streaming previews recompute on every streamed chunk; re-reading the target
* file from disk each tick dominates the cost on large files. Cache the raw
* section text keyed by mtime+size so any on-disk change invalidates
* naturally. Used by the streaming path only — the args-complete pass always
* reads fresh.
*/
const streamingTextCache = new Map<string, { mtimeMs: number; size: number; rawContent: string }>();
const STREAMING_TEXT_CACHE_MAX = 8;
async function readSectionTextCached(absolutePath: string, sectionPath: string): Promise<string> {
let stamp: { mtimeMs: number; size: number } | undefined;
try {
const stat = await Bun.file(absolutePath).stat();
stamp = { mtimeMs: stat.mtimeMs, size: stat.size };View on GitHub (pinned to 9690622007)
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).
Example fix
// before
hashlineEdit({ section: `@@@ src/oldName.ts:tag\n- old line` });
// after
// after rename, re-read to get fresh path+tag:
hashlineEdit({ section: `@@@ src/newName.ts:a1b2\n- old line` }); Defensive patterns
Strategy: try-catch
Validate before calling
const stat = await Bun.file(sectionPath.replace(/:[0-9a-f]+$/, '')).exists();
if (!stat) throw new Error(`Section path does not exist: ${sectionPath}`); Try / catch
try {
const raw = await readSectionText(absPath, sectionPath);
return applyEdits(raw);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (msg.includes('Unable to read') || msg.includes('File not found')) {
return reReadAndReauthorEdit(sectionPath);
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- File not found: ${relativePath}
- I/O error occurred
- {}
- Missing hashline snapshot tag for ${sectionPath}; use `${HL_
- Multiple hashline sections resolve to the same file (${previ
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b7bb698cfc2d5282.
Report an issue: GitHub.