can1357/oh-my-pi · error
${referenceSeparator} after MATCH reads as the ${REWRITE_HEA
Error message
${referenceSeparator} after MATCH reads as the ${REWRITE_HEADER} separator, leaving REWRITE empty.\nCopy-ready corrected payload (fill in the final text):\n${correctedLines.join("\n")} What it means
When a MATCH operation is followed by a line equal to the » separator, the separator would terminate the pattern and leave an empty REWRITE. The parser detects this recoverable mistake and throws an error that embeds a copy-ready corrected payload: the erroneous separator line is replaced with » and a '<final text>' placeholder is inserted, so the caller can fill in the replacement and re-send.
Source
Thrown at packages/coding-agent/src/edit/sloppy.ts:1173
let patternLines: string[] = [];
let rewriteLines: string[] = [];
let referenceSeparator: string | undefined;
const finish = (endIndex: number) => {
const sourcePatternText = normalizeBlock(patternLines, false);
const rewriteText = normalizeBlock(rewriteLines, true);
if (referenceSeparator !== undefined && rewriteText.trim() === "") {
// A trailing »N produced no rewrite: noise after an inline operation;
// after a legacy MATCH the final text is missing — hand back a
// fill-in skeleton instead of echoing the broken payload.
if (!hasInlineSelection(sourcePatternText)) {
const correctedLines = [...lines];
const separatorIndex = correctedLines.findLastIndex(
(line, index) => index < endIndex && line.trim() === referenceSeparator,
);
correctedLines[separatorIndex] = REWRITE_HEADER;
correctedLines.splice(endIndex, 0, "<final text>");
throw new Error(
`${referenceSeparator} after MATCH reads as the ${REWRITE_HEADER} separator, leaving REWRITE empty.\nCopy-ready corrected payload (fill in the final text):\n${correctedLines.join("\n")}`,
);
}
operations.push(createOperation(sourcePatternText, "", allMatches, operations.length + 1, false));
return;
}
operations.push(createOperation(sourcePatternText, rewriteText, allMatches, operations.length + 1, true));
};
const pendingSeparatorErrors = new Map<number, string>();
const finishPattern = (endIndex: number) => {
const sourcePatternText = normalizeBlock(patternLines, false);
if (
hasInlineSelection(sourcePatternText) ||
hasMarkerLines(sourcePatternText) ||
hasBareDesired(sourcePatternText)
) {
operations.push(createOperation(sourcePatternText, "", allMatches, operations.length + 1, false));
return;View on GitHub (pinned to 9690622007)
Solutions
- Use the corrected payload printed in the error: keep the » header line and fill in '<final text>' after it
- If no rewrite is intended, delete the bare » line so the MATCH stays pattern-only (or use allMatches form)
- Re-send the full payload — operations apply atomically
Example fix
// before § MATCH old text » // after § MATCH old text » <final text>
Defensive patterns
Strategy: validation
Validate before calling
const lines = payload.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim() === '»' && lines[i + 1] === undefined) {
throw new Error('bare » line terminates MATCH with an empty REWRITE');
}
} Try / catch
try {
applySloppy(content, input, ctx);
} catch (err) {
if (err instanceof Error && err.message.includes('reads as the » separator')) {
const corrected = err.message.match(/Copy-ready corrected payload[\s\S]*/)?.[0];
// fill '<final text>' in corrected payload and re-send
} else throw err;
} Prevention
- Never use a bare » line as a visual divider — it is the REWRITE header
- Follow every » header with the replacement text
- If no rewrite is needed, omit the separator entirely (pattern-only MATCH)
When it happens
Trigger: A payload where a MATCH section's pattern is terminated by a line consisting solely of » (the reference separator) instead of the » rewrite header, producing an empty rewrite body.
Common situations: An LLM uses a bare '»' line as a section divider without knowing it doubles as the REWRITE header; copy/paste collapses '» rewrite' into just '»'.
Related errors
- lines.join("\n")
- Operation ${operationNumber} has an unclosed selection marke
- Operation ${operationNumber} has an unmatched closing select
- Operation ${operationNumber} has nested selection markers; u
- Operation ${operationNumber} mixes inline and bare selection
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/eb71287d9a5b7c63.
Report an issue: GitHub.