{"record":{"id":"44f5f5b247b251b5","repo":"can1357/oh-my-pi","slug":"the-first-line-of-the-patch-must-be-begin-pat","errorCode":null,"errorMessage":"The first line of the patch must be '*** Begin Patch'","messagePattern":"The first line of the patch must be '\\*\\*\\* Begin Patch'","errorType":"validation","errorClass":"ParseError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/apply-patch/parser.ts","lineNumber":71,"sourceCode":"}\n\nfunction parseApplyPatchWithOptions(patchText: string, options: ParseApplyPatchOptions): PatchInput[] {\n\tconst streaming = options.streaming === true;\n\tlet lines = patchText.trim().split(\"\\n\");\n\n\t// Lenient heredoc strip: <<EOF / <<'EOF' / <<\"EOF\" ... EOF\n\tif (lines.length >= 2) {\n\t\tconst first = lines[0];\n\t\tconst last = lines[lines.length - 1].trim();\n\t\tconst validOpeners = new Set([\"<<EOF\", \"<<'EOF'\", '<<\"EOF\"']);\n\t\tif (validOpeners.has(first) && last === \"EOF\") {\n\t\t\tlines = lines.slice(1, lines.length - 1);\n\t\t}\n\t}\n\n\tif (lines.length === 0 || lines[0].trim() !== BEGIN_PATCH_MARKER) {\n\t\tif (streaming) return [];\n\t\tthrow new ParseError(\"The first line of the patch must be '*** Begin Patch'\");\n\t}\n\tconst hasEndMarker = lines[lines.length - 1].trim() === END_PATCH_MARKER;\n\tif (!hasEndMarker && !streaming) {\n\t\tthrow new ParseError(\"The last line of the patch must be '*** End Patch'\");\n\t}\n\n\tconst hunks: PatchInput[] = [];\n\tlet remaining = hasEndMarker ? lines.slice(1, lines.length - 1) : lines.slice(1);\n\t// Line numbers are 1-based and include the `*** Begin Patch` line (= 1).\n\tlet lineNumber = 2;\n\n\twhile (remaining.length > 0) {\n\t\t// Blank separator lines between hunks are ignored (spec §3.3).\n\t\tif (remaining[0].trim() === \"\") {\n\t\t\tremaining = remaining.slice(1);\n\t\t\tlineNumber++;\n\t\t\tcontinue;\n\t\t}","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/apply-patch/parser.ts#L53-L89","documentation":"The apply-patch parser requires the literal marker '*** Begin Patch' as the first non-dropped line of the patch. In non-streaming mode a missing marker is a hard ParseError; in streaming mode it returns [] (waiting for more data). This guards against feeding arbitrary text into the patch format.","triggerScenarios":"Calling parseApplyPatch (via applyCodexPatch) with text whose first line is not exactly '*** Begin Patch' (after trim) — e.g. a model prefixed the patch with prose or a code fence, or used lowercase/variant markers.","commonSituations":"LLM output wrapped the patch in ``` fences so the first line is '```'; leading explanation text before the marker; copied patch lost its first line; applying a unified-diff (--- a/...) instead of a codex patch.","solutions":["Ensure the patch text begins with the exact line '*** Begin Patch' (no fences, no leading prose)","Strip markdown code fences and any preamble before the marker before parsing","If the input might be a unified diff, route it to the unified-diff applier instead","Catch ParseError and, for model-generated patches, re-request the patch in the correct format"],"exampleFix":"// before\nawait applyCodexPatch('```\\n*** Begin Patch\\n...\\n```');\n// after\nconst stripped = patchText.replace(/^```[a-z]*\\n/, '').replace(/\\n```$/, '');\nawait applyCodexPatch(stripped.trimStart());","handlingStrategy":"try-catch","validationCode":"if (!patchText.trimStart().startsWith('*** Begin Patch')) {\n\tthrow new SkipOperation('not a codex patch');\n}","typeGuard":"function isCodexPatch(text) { return text.trimStart().startsWith('*** Begin Patch'); }","tryCatchPattern":"try {\n\tawait applyCodexPatch(patchText);\n} catch (err) {\n\tif (err instanceof ParseError && err.message.includes(\"'*** Begin Patch'\")) {\n\t\tpatchText = stripFencesAndPreamble(patchText);\n\t\tawait applyCodexPatch(patchText);\n\t}\n}","preventionTips":["Strip markdown fences from model output","Instruct models to output the patch with no surrounding prose","Validate the first line before parsing"],"tags":["patch","parser","format-validation","llm-output"],"backgroundTag":"malformed-patch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}