can1357/oh-my-pi · error · Error
unseenLinesMessage(section.path, unseen, expected, { lines:
Error message
unseenLinesMessage(section.path, unseen, expected, { lines: revealed, truncated }) What it means
#assertSeenLines enforces that every line a hashline patch will edit was actually revealed to the caller in a prior read. If some expected lines were never seen, it throws unseenLinesMessage listing the section, unseen lines, and what was revealed, preventing blind edits against unobserved content. If the reveal was column-truncated, seen lines are not credited, forcing a full-range re-read.
Source
Thrown at packages/hashline/src/patcher.ts:653
if (line < 1 || line > sourceLines.length) continue;
const source = sourceLines[line - 1] ?? "";
if (source.length > SEEN_LINE_REVEAL_MAX_COLUMNS) {
revealed.push({ line, text: `${source.slice(0, SEEN_LINE_REVEAL_MAX_COLUMNS)}…` });
columnTruncated = true;
} else {
revealed.push({ line, text: source });
}
}
const truncated = unseen.length > revealed.length || columnTruncated;
// Only merge when the reveal covered every unseen anchor line in full
// width. A prefix-truncated reveal would let the model split a blind
// edit into <=cap-line retries and land it without ever running the
// required range re-read; a column-clipped reveal would leave part of
// each line unseen while the model receives an "ok to retry" signal.
if (!truncated) {
for (const { line } of revealed) seen.add(line);
}
throw new Error(unseenLinesMessage(section.path, unseen, expected, { lines: revealed, truncated }));
}
#mismatchError(
section: PatchSection,
canonicalPath: string,
normalized: string,
expected: string,
hashRecognized: boolean,
): MismatchError {
const actualFileHash = this.#recordFullSnapshot(canonicalPath, normalized);
return new MismatchError({
path: section.path,
expectedFileHash: expected,
actualFileHash,
fileLines: normalized.split("\n"),
anchorLines: section.collectAnchorLines(),
hashRecognized,
});
}View on GitHub (pinned to 9690622007)
Solutions
- Re-read the target section (full lines, within the column cap) before retrying the edit
- Retry the edit so the re-read marks the lines as seen, then re-issue the patch
- Avoid clipped/truncated reads of the lines you intend to edit
- If the file changed externally, restart the read-edit cycle from a fresh read
Example fix
// before applyPatch(edits); // lines 40-45 never read → throws // after const section = readSection(path, 40, 45); // full, untruncated read applyPatch(edits); // lines now marked seen
Defensive patterns
Strategy: try-catch
Try / catch
try {
applyPatch(edits);
} catch (e) {
if (e.message.includes("were never read") || /unseen/i.test(e.message)) {
await readSection(path, startLine, endLine); // full, untruncated read
applyPatch(edits); // retry after lines are marked seen
}
} Prevention
- Always read the exact lines you intend to edit immediately before editing
- Avoid truncated/clipped reads for regions that will be patched
- Re-read after any external file change; never retry edits blind
- Track which ranges were revealed and pre-check patch anchors against them
When it happens
Trigger: Applying a hashline patch to lines that were never included in a prior read of the section, or where prior reads were truncated (row cap or column clipping) so the patcher cannot confirm those lines were seen.
Common situations: An agent retrying an edit without re-reading the target region, read results capped by line/width limits, editing a different section of a file after only reading part of it, or stale session state after the file changed on disk.
Related errors
- Line ${anchor.line} does not exist (file has ${fileLines.len
- `PUT ${startLine}.=${endLine}:` rejected: a selected boundar
- directory stack is empty
- No messages to continue from
- Cannot continue from message role: assistant
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/19dd1f23d4662f3e.
Report an issue: GitHub.