{"record":{"id":"21db8fdf4571a223","repo":"can1357/oh-my-pi","slug":"expected-hunk-to-start-with-context-marker-got","errorCode":null,"errorMessage":"Expected hunk to start with @@ context marker, got: '${lines[0]}'","messagePattern":"Expected hunk to start with @@ context marker, got: '(.+?)'","errorType":"validation","errorClass":"ParseError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/edit/diff.ts","lineNumber":611,"sourceCode":"\t\t\tif (oldStartLine < 1) {\n\t\t\t\tthrow new ParseError(\"Line hint must be >= 1\", lineNumber);\n\t\t\t}\n\t\t} else if (TOP_OF_FILE_REGEX.test(normalizedContextValue)) {\n\t\t\toldStartLine = 1;\n\t\t\tnewStartLine = 1;\n\t\t} else if (trimmedContextValue.length > 0) {\n\t\t\tchangeContexts.push(contextValue);\n\t\t}\n\t\tstartIndex = 1;\n\t} else if (isHeaderLine) {\n\t\tconst contextValue = headerTrimmed.slice(2).trim();\n\t\tif (contextValue.length > 0) {\n\t\t\tchangeContexts.push(contextValue);\n\t\t}\n\t\tstartIndex = 1;\n\t} else {\n\t\tif (!allowMissingContext) {\n\t\t\tthrow new ParseError(`Expected hunk to start with @@ context marker, got: '${lines[0]}'`, lineNumber);\n\t\t}\n\t\tstartIndex = 0;\n\t}\n\n\tif (oldStartLine !== undefined && oldStartLine < 1) {\n\t\tthrow new ParseError(`Line numbers must be >= 1 (got ${oldStartLine})`, lineNumber);\n\t}\n\tif (newStartLine !== undefined && newStartLine < 1) {\n\t\tthrow new ParseError(`Line numbers must be >= 1 (got ${newStartLine})`, lineNumber);\n\t}\n\n\twhile (startIndex < lines.length) {\n\t\tconst nextLine = lines[startIndex];\n\t\tif (!nextLine.startsWith(\"@@\")) {\n\t\t\tbreak;\n\t\t}\n\t\tconst trimmed = nextLine.trimEnd();\n\t\tif (trimmed.startsWith(CHANGE_CONTEXT_MARKER)) {","sourceCodeStart":593,"sourceCodeEnd":629,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/edit/diff.ts#L593-L629","documentation":"Thrown when parseOneHunk is called with allowMissingContext=false and the first line of the candidate hunk does not start with '@@' at all. The parser expects every hunk to begin with an '@@' context/line-number marker (unified header, '@@ <context>' form, or empty '@@ @@'); anything else is rejected so content lines are never silently mis-attributed. Callers that allow context-less hunks pass allowMissingContext=true and skip this error.","triggerScenarios":"Calling parseDiffHunks on a diff whose first hunk line is raw content ('+foo', ' context', or a file marker) instead of an '@@' header; passing a stray text fragment where a hunk is expected.","commonSituations":"Patches missing the header because an editor stripped lines starting with '@'; models emitting only +/- lines; splitting a multi-file patch incorrectly so a content line becomes a hunk start.","solutions":["Add the missing '@@' header line at the start of the hunk (e.g. '@@@ filename @@' or a unified '@@ -a,b +c,d @@').","Check that the diff was split into hunks/files correctly before parsing each part.","If header-less hunks are acceptable in your pipeline, use the parse path with allowMissingContext=true.","Inspect the first line printed in the message — it shows exactly what the parser saw."],"exampleFix":"// before\n+console.log(\"hi\")\n// after\n@@ -1 +1 @@\n+console.log(\"hi\")","handlingStrategy":"validation","validationCode":"const first = diff.trimStart().split(\"\\n\")[0];\nif (first !== undefined && !first.startsWith(\"@@\")) {\n  throw new Error(`Hunk must start with '@@' header, got: ${JSON.stringify(first.slice(0, 40))}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  hunks = parseDiffHunks(diff);\n} catch (err) {\n  if (err instanceof ParseError && err.message.startsWith(\"Expected hunk to start with @@\")) {\n    // show the offending line; ask the generator/model to re-emit with a header\n  } else throw err;\n}","preventionTips":["Verify every hunk begins with an '@@' line before parsing.","Don't split multi-hunk patches at arbitrary offsets — split only at '@@' boundaries.","Preserve leading characters when copying diffs (avoid markdown reflow)."],"tags":["diff","parsing","malformed-input"],"backgroundTag":"missing-hunk-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}