{"record":{"id":"5aa9aac2ba35a075","repo":"vxcontrol/pentagi","slug":"invalid-hunk-header-q","errorCode":null,"errorMessage":"invalid hunk header: %q","messagePattern":"invalid hunk header: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/file_diff.go","lineNumber":76,"sourceCode":"\n\ti := 0\n\tfor i < len(lines) && !strings.HasPrefix(lines[i], \"@@\") {\n\t\ttrimmed := strings.TrimSpace(lines[i])\n\t\tif trimmed != \"\" && !strings.HasPrefix(trimmed, \"---\") && !strings.HasPrefix(trimmed, \"+++\") {\n\t\t\treturn nil, fmt.Errorf(\"expected a hunk header (\\\"@@ -old +new @@\\\") but found: %q\", lines[i])\n\t\t}\n\t\ti++\n\t}\n\tif i >= len(lines) {\n\t\treturn nil, fmt.Errorf(`diff contains no hunks (no \"@@ ... @@\" header found)`)\n\t}\n\n\tvar hunks []diffHunk\n\tfor i < len(lines) {\n\t\theader := lines[i]\n\t\tm := unifiedDiffHunkHeaderRe.FindStringSubmatch(header)\n\t\tif m == nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid hunk header: %q\", header)\n\t\t}\n\t\thunk := diffHunk{header: header, oldStart: 1}\n\t\tif m[1] != \"\" {\n\t\t\toldStart, err := strconv.Atoi(m[1])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid hunk header %q: %w\", header, err)\n\t\t\t}\n\t\t\thunk.oldStart = oldStart\n\t\t\thunk.hasPosition = true\n\t\t}\n\t\ti++\n\n\t\tfor i < len(lines) && !strings.HasPrefix(lines[i], \"@@\") {\n\t\t\tline := lines[i]\n\t\t\ti++\n\n\t\t\tif strings.HasPrefix(line, `\\`) {\n\t\t\t\t// e.g. \"\\ No newline at end of file\" - not a content line.","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/file_diff.go#L58-L94","documentation":"Once parseUnifiedDiff reaches what should be a hunk header, it matches the line against unifiedDiffHunkHeaderRe. A line that fails the regex (e.g. '@@ -abc +def @@' or a stray line inside the diff body) causes this error. It is a strict format check on the '@@ -old +new @@' syntax.","triggerScenarios":"A line between file headers and body was expected to be a hunk header but is not — e.g. '@@ -x +y @@' with non-numeric line numbers, a truncated header like '@@ -1 +1', or a random content line after the ---/+++ preamble.","commonSituations":"LLM-generated diffs with hand-typed hunk headers (wrong numbers of fields, 'l' instead of '1'); diffs copied from logs where header characters were mangled; tools emitting context-diff format instead of unified format.","solutions":["Look at the quoted header in the error and fix its syntax to '@@ -<oldStart>[,<oldCount>] +<newStart>[,<newCount>] @@'.","Regenerate the diff with a real diff tool (git diff -U3) rather than hand-writing hunk headers.","Verify no unrelated lines slipped between the file header and the first hunk header.","Check line endings — headers split across '\\r\\n' boundaries may fail matching; normalize to '\\n'."],"exampleFix":"// before\n\"@@ -one,2 +1,2 @@\"\n\n// after\n\"@@ -1,2 +1,2 @@\"","handlingStrategy":"validation","validationCode":"var hunkHeaderRe = regexp.MustCompile(`^@@ -\\d+(,\\d+)? \\+\\d+(,\\d+)? @@`)\nfunc headersValid(diff string) bool {\n\tfor _, line := range strings.Split(diff, \"\\n\") {\n\t\tif strings.HasPrefix(line, \"@@\") && !hunkHeaderRe.MatchString(line) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":"if _, _, err := ApplyUnifiedDiff(ctx, path, diff); err != nil {\n\tvar badHeader string\n\tif m := regexp.MustCompile(`invalid hunk header: \"([^\"]*)\"`).FindStringSubmatch(err.Error()); m != nil {\n\t\tbadHeader = m[1] // surface to user/regeneration prompt\n\t}\n\treturn fmt.Errorf(\"diff rejected (bad header %q): %w\", badHeader, err)\n}","preventionTips":["Never hand-write hunk headers; use git diff output as-is","Pre-validate any line starting with @@ against the hunk-header regex","Normalize line endings to \\n before parsing","When an LLM writes diffs, require it to echo git diff output verbatim"],"tags":["diff","parsing","unified-diff","regex"],"backgroundTag":"invalid-hunk-header","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}