can1357/oh-my-pi · error
Invalid control line ${JSON.stringify(trimmed)}; use only ${
Error message
Invalid control line ${JSON.stringify(trimmed)}; use only ${OPENER}, ${OPENER}*, ${REWRITE_HEADER}, or ${REWRITE_HEADER}N in REWRITE. What it means
Lines that begin with a control marker (« or ») must be exactly one of the four legal control lines: «, «*, », or »N (a register reference). Anything else starting with those glyphs — e.g. «/path/to/file, « some comment, »! — is rejected so malformed payloads fail loudly instead of being silently parsed as literal text. The offending line is echoed with JSON.stringify for exactness.
Source
Thrown at packages/coding-agent/src/edit/sloppy.ts:1328
const trimmed = line.trim();
const registerReference = trimmed.match(/^»([1-9]\d*)$/u);
if (isOrdinalOpener(line)) {
throw new Error(
`${trimmed} is not a valid opener. Use ${OPENER} with a pattern that matches once — add context only the intended match has — or ${OPENER}* to change every match.`,
);
}
if (trimmed === `${OPENER}${REWRITE_HEADER}`) {
// A glued «» line: after MATCH content it is a mistyped » separator;
// anywhere else it is a stray operation terminator to drop.
if (state === "pattern" && patternLines.some(entry => entry.trim() !== "")) state = "rewrite";
continue;
}
if (
parsedOpener === false &&
(trimmed.startsWith(OPENER) ||
(trimmed.startsWith(REWRITE_HEADER) && trimmed !== REWRITE_HEADER && !registerReference))
) {
throw new Error(
`Invalid control line ${JSON.stringify(trimmed)}; use only ${OPENER}, ${OPENER}*, ${REWRITE_HEADER}, or ${REWRITE_HEADER}N in REWRITE.`,
);
}
if (state === "outside") {
if (parsedOpener !== false) {
allMatches = parsedOpener === 0;
patternLines = [];
rewriteLines = [];
referenceSeparator = undefined;
state = "pattern";
} else if (trimmed !== "") {
throw new Error(`Expected ${OPENER} on input line ${index + 1}.`);
}
continue;
}
if (state === "pattern") {
const accumulated = patternLines.join("\n");View on GitHub (pinned to 9690622007)
Solutions
- Make the line exactly « (unique match), «* (all matches), » (start rewrite), or »N (reference earlier operation) — nothing else on the line.
- If you meant a file path header, use the § section opener format (e.g. §path/to/file.ts) instead of gluing it to «.
- If the line is literal file content that happens to start with « or », rephrase or re-indent it so the payload is unambiguous.
Example fix
// before «main.ts pattern » replacement // after §main.ts « pattern » replacement
Defensive patterns
Strategy: validation
Validate before calling
for (const line of body.split("\n")) {
const t = line.trim();
if ((t.startsWith("«") || t.startsWith("»")) && !["«", "«*", "»"].includes(t) && !/^»[1-9]\d*$/.test(t)) {
throw new Error(`invalid control line: ${t}`);
}
} Type guard
const isLegalControlLine = (t: string): boolean => t === "«" || t === "«*" || t === "»" || /^»[1-9]\d*$/.test(t);
Try / catch
catch (err) {
if (err instanceof Error && err.message.startsWith("Invalid control line")) {
const bad = JSON.parse(err.message.match(/Invalid control line (".*?")/)?.[1] ?? '""');
// strip or fix the offending line and retry
}
} Prevention
- Put file paths in § section headers, never after «.
- Keep control marker lines bare: «, «*, », »N with nothing else.
- Escape or re-indent literal content that begins with « or ».
When it happens
Trigger: A line inside the section body starts with « or » but is not exactly «, «*, », or »[1-9] — e.g. «file.ts headers carried over from other formats, «foo arguments glued to the opener, or «*2 mixed variants.
Common situations: Models gluing file paths or parameters onto openers («main.ts); leftover headers from apply-patch-style payloads; typos like «* * or «*2; pasted text containing the guillemet characters mid-payload.
Related errors
- needsSeparator (Operation ${operations.length + 1} needs ${R
- ${trimmed} is not a valid opener. Use ${OPENER} with a patte
- Expected ${OPENER} on input line ${index + 1}.
- ${trimmed} is valid only in REWRITE, never MATCH.
- Operation ${operations.length + 1} has a second ${REWRITE_HE
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a7e0bd54a1c91d16.
Report an issue: GitHub.