can1357/oh-my-pi · error
Operation ${operationNumber} has an empty pattern.
Error message
Operation ${operationNumber} has an empty pattern. What it means
parsePattern validates each operation's MATCH text. An operation whose pattern is blank (only whitespace) after the « opener carries no information about what to replace, so it is rejected with the operation number. A sibling error ("has no visible current text") covers patterns whose characters are all stripped by normalization. validateSelectionMarkers then checks ⟪...⟫ selection markers.
Source
Thrown at packages/coding-agent/src/edit/sloppy.ts:1479
starts.push(index);
ends.push(next);
}
}
index = next;
}
return { text, starts, ends };
}
function patternGapAt(source: string, offset: number): string | undefined {
return source.startsWith(GAP, offset) ? GAP : undefined;
}
function patternContainsGap(source: string): boolean {
return source.includes(GAP);
}
function parsePattern(pattern: string, operationNumber: number): ParsedPattern {
if (pattern.trim() === "") throw new Error(`Operation ${operationNumber} has an empty pattern.`);
validateSelectionMarkers(pattern, operationNumber);
const hasGap = patternContainsGap(pattern);
const hasSelection = pattern.includes(SELECT_OPEN);
if (!hasGap && !hasSelection) {
const normalized = normalizeText(pattern).text;
if (normalized === "") throw new Error(`Operation ${operationNumber} has no visible current text.`);
return {
tokens: [{ kind: "literal", text: pattern, normalized }],
selectionStart: 0,
selectionEnd: 1,
insertion: false,
lineInsertion: false,
selectedCaptureIndices: [],
selectionRanges: [],
selectionPairs: [],
literalFallback: undefined,
};
}View on GitHub (pinned to 9690622007)
Solutions
- Put the exact current text to be replaced between « and » — the pattern must have non-whitespace content.
- For an insertion, include the anchor line before the insertion point as the pattern and emit anchor+new text in the rewrite.
- Check the payload wasn't truncated or stripped of its pattern lines between generation and apply.
Example fix
// before « » new text // after « anchor line » anchor line new text
Defensive patterns
Strategy: validation
Validate before calling
// per-operation: pattern must contain visible text
const ops = body.split(/^«\*?$/m).slice(1);
for (let i = 0; i < ops.length; i++) {
const pattern = ops[i].split(/^»/m)[0];
if (pattern.trim() === "") throw new Error(`operation ${i + 1} has an empty pattern`);
} Type guard
const hasVisiblePattern = (op: string): boolean => op.split(/^»/m)[0].trim() !== "";
Try / catch
catch (err) {
if (err instanceof Error && err.message.includes("has an empty pattern")) {
// regenerate the operation with an anchored match block
}
} Prevention
- Never emit « directly followed by » — every operation needs current text to match.
- Model insertions as pattern = anchor line, rewrite = anchor + inserted text.
- Use this format only for edits to existing files; file creation belongs to the add-file section mechanism.
When it happens
Trigger: A payload with « followed immediately by » (empty match), or a match block containing only spaces/tabs/newlines; also occurs when a model emits the opener and separator back-to-back intending an insertion-only edit.
Common situations: Models attempting pure insertions with an empty MATCH block; truncated payloads where pattern lines were lost; whitespace-only bodies after copy-paste; using this format for file creation instead of the proper add mechanism.
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/b2fb075741d8c89d.
Report an issue: GitHub.