can1357/oh-my-pi · error
message (pending separator error, justified-check failure)
Error message
message (pending separator error, justified-check failure)
What it means
When a pattern-only block was optimistically interpreted as a deletion (assumedDeletion, error 1220's sibling path), the parser records the would-be "needs separator" error as pending. After parsing, it keeps the deletion only if justified: some later operation's rewrite re-emits the deleted text verbatim (normalized) or references this operation via »N — i.e. it looks like the delete-half of a move. If not justified, the saved error message is thrown as-is.
Source
Thrown at packages/coding-agent/src/edit/sloppy.ts:1432
throw new Error(
`${REWRITE_HEADER}${reference[1]} must reference an earlier operation, not self/forward.`,
);
}
}
}
}
for (const [index, message] of pendingSeparatorErrors) {
const patternNormalized = normalizeText(operations[index].patternText).text;
const justified = operations.some((other, otherIndex) => {
if (otherIndex === index) return false;
const rewrites = other.rewrite.kind === "explicit" ? [other.rewrite.text] : other.rewrite.replacements;
return rewrites.some(
rewrite =>
normalizeText(rewrite).text.includes(patternNormalized) ||
rewrite.split("\n").some(line => line.trim() === `${REWRITE_HEADER}${index + 1}`),
);
});
if (!justified) throw new Error(message);
}
return operations;
}
function normalizeText(source: string): NormalizedText {
let text = "";
const starts: number[] = [];
const ends: number[] = [];
for (let index = 0; index < source.length; ) {
const codePoint = source.codePointAt(index);
if (codePoint === undefined) break;
if (codePoint <= 0x7f) {
const next = index + 1;
if (!((codePoint >= 0x09 && codePoint <= 0x0d) || codePoint === 0x20)) {
text += source[index];
starts.push(index);
ends.push(next);
}View on GitHub (pinned to 9690622007)
Solutions
- Add an explicit «» separator: if it's a rewrite, put the new text after »; if it's a true deletion, leave the rewrite empty — explicit intent is always accepted.
- If this is part of a move, ensure the later operation's rewrite contains the deleted text (matching after normalization) or a »N reference to this operation.
- Paste the corrected payload from the thrown message, filling in <new text>.
Example fix
// before (ambiguous pattern-only block) « long block of text « new location text » long block of text // after (explicit move) « long block of text » « new location text » long block of text
Defensive patterns
Strategy: try-catch
Try / catch
try {
const result = await computeSloppySectionDiff(section, cwd);
if ("error" in result) {
// this error surfaces with the full copy-ready corrected payload;
// resubmit it with <new text> filled in (or keep the deletion explicit
// via an empty rewrite after »)
}
} catch (err) {
if (err instanceof Error && err.message.includes("needs »")) { /* handle */ }
} Prevention
- Never rely on the assumed-deletion heuristic; always pair pattern-only blocks with an explicit empty rewrite (» with nothing after).
- For moves, make the re-emit byte-identical after normalization or use a »N reference.
- Treat any "pending separator" design as last-resort; generate explicit separators in your authoring pipeline.
When it happens
Trigger: A payload contains a multi-line pattern-only block (>= 24 normalized chars) with no «» separator, and no subsequent operation re-includes that text in its rewrite or issues »N pointing back at it — the parser cannot confirm the deletion was intentional.
Common situations: Models omitting «» for a true deletion of a long block (rejected as too risky to guess); intended moves where the re-emit didn't match exactly (whitespace/wording drift); deletions the author actually meant as rewrites.
Related errors
- needsSeparator (Operation ${operations.length + 1} needs ${R
- ${trimmed} is not a valid opener. Use ${OPENER} with a patte
- Invalid control line ${JSON.stringify(trimmed)}; use only ${
- Expected ${OPENER} on input line ${index + 1}.
- ${trimmed} is valid only in REWRITE, never MATCH.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/09c15cdc45e34813.
Report an issue: GitHub.