{"record":{"id":"a9c063c557af03fe","repo":"can1357/oh-my-pi","slug":"operation-operations-length-1-has-a-second","errorCode":null,"errorMessage":"Operation ${operations.length + 1} has a second ${REWRITE_HEADER} line.","messagePattern":"Operation (.+?) has a second (.+?) line\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/sloppy.ts","lineNumber":1389,"sourceCode":"\t\t\t} else {\n\t\t\t\tpatternLines.push(line);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (parsedOpener !== false) {\n\t\t\tfinish(index);\n\t\t\tallMatches = parsedOpener === 0;\n\t\t\tpatternLines = [];\n\t\t\trewriteLines = [];\n\t\t\treferenceSeparator = undefined;\n\t\t\tstate = \"pattern\";\n\t\t} else if (trimmed === \"***\") {\n\t\t\t// Stray apply-patch structure inside REWRITE; never final text.\n\t\t} else if (trimmed === REWRITE_HEADER) {\n\t\t\tconst nextContent = lines.slice(index + 1).find(entry => entry.trim() !== \"\");\n\t\t\tif (nextContent !== undefined && parseOpener(nextContent) === false) {\n\t\t\t\tthrow new Error(`Operation ${operations.length + 1} has a second ${REWRITE_HEADER} line.`);\n\t\t\t}\n\t\t\t// A bare » before the next operation or at payload end is a stray\n\t\t\t// close-bracket: models sometimes wrap both MATCH and REWRITE in «…».\n\t\t} else if (\n\t\t\ttrimmed === SELECT_CLOSE &&\n\t\t\t(rewriteLines.join(\"\\n\").match(/⟪/gu) || []).length === (rewriteLines.join(\"\\n\").match(/⟫/gu) || []).length\n\t\t) {\n\t\t\t// A lone ⟫ with no open selection is a stray block terminator; REWRITE\n\t\t\t// is final text and never carries selection markers.\n\t\t} else {\n\t\t\trewriteLines.push(line);\n\t\t}\n\t}\n\n\tif (state === \"rewrite\") finish(lines.length);\n\telse if (state === \"pattern\") finishPattern(lines.length);\n\tif (operations.length === 0) throw new Error(`Empty patch. Start with ${OPENER}.`);\n\tfor (let index = 0; index < operations.length; index++) {","sourceCodeStart":1371,"sourceCodeEnd":1407,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/sloppy.ts#L1371-L1407","documentation":"Each operation may contain exactly one » (REWRITE) header. When the parser sees a second bare » inside the rewrite state AND the next non-blank line is not a new « opener, it concludes a second rewrite block was attempted for the same operation and throws. If the next content line is a valid opener, the stray » is instead forgiven as a close-bracket artifact (models sometimes wrap MATCH and REWRITE in «...»).","triggerScenarios":"An operation whose rewrite text is followed by another bare » line with more non-opener content after it — e.g. the author splitting the replacement into two »-delimited chunks, or double-closing with » ... » followed by more text.","commonSituations":"Models wrapping both halves in « ... » and emitting two closing markers; splitting a large rewrite into multiple » sections; copy-paste duplicating the separator line.","solutions":["Remove the duplicate » line; keep exactly one per operation.","Merge both replacement chunks into a single block after one ».","If a second change is intended, start a new operation with its own « opener."],"exampleFix":"// before\n«\npattern\n»\nfirst part\n»\nsecond part\n\n// after\n«\npattern\n»\nfirst part\nsecond part","handlingStrategy":"validation","validationCode":"const sepCount = (body.match(/^»$/gm) || []).length;\nconst opCount = (body.match(/^«\\*?$/gm) || []).length;\nif (sepCount > opCount + /* tolerated artifacts */ 0) console.warn(\"possible duplicate » line\");","typeGuard":"const exactlyOneSeparator = (op: string[]): boolean => op.filter(l => l.trim() === \"»\").length === 1;","tryCatchPattern":"catch (err) {\n  if (err instanceof Error && err.message.includes(\"has a second » line\")) {\n    // merge the split rewrite blocks and resubmit\n  }\n}","preventionTips":["One » per operation — never split a rewrite across multiple » blocks.","Don't wrap MATCH and REWRITE in « ... »; the format is « ... » ... not bracketed.","Lint generated payloads: count » lines and compare against « count."],"tags":["parser","edit-format","duplicate-separator"],"backgroundTag":"missing-section-separator","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}