vxcontrol/pentagi · error
invalid hunk header: %q
Error message
invalid hunk header: %q
What it means
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.
Source
Thrown at backend/pkg/tools/file_diff.go:76
i := 0
for i < len(lines) && !strings.HasPrefix(lines[i], "@@") {
trimmed := strings.TrimSpace(lines[i])
if trimmed != "" && !strings.HasPrefix(trimmed, "---") && !strings.HasPrefix(trimmed, "+++") {
return nil, fmt.Errorf("expected a hunk header (\"@@ -old +new @@\") but found: %q", lines[i])
}
i++
}
if i >= len(lines) {
return nil, fmt.Errorf(`diff contains no hunks (no "@@ ... @@" header found)`)
}
var hunks []diffHunk
for i < len(lines) {
header := lines[i]
m := unifiedDiffHunkHeaderRe.FindStringSubmatch(header)
if m == nil {
return nil, fmt.Errorf("invalid hunk header: %q", header)
}
hunk := diffHunk{header: header, oldStart: 1}
if m[1] != "" {
oldStart, err := strconv.Atoi(m[1])
if err != nil {
return nil, fmt.Errorf("invalid hunk header %q: %w", header, err)
}
hunk.oldStart = oldStart
hunk.hasPosition = true
}
i++
for i < len(lines) && !strings.HasPrefix(lines[i], "@@") {
line := lines[i]
i++
if strings.HasPrefix(line, `\`) {
// e.g. "\ No newline at end of file" - not a content line.View on GitHub (pinned to ea665308ba)
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'.
Example fix
// before "@@ -one,2 +1,2 @@" // after "@@ -1,2 +1,2 @@"
Defensive patterns
Strategy: validation
Validate before calling
var hunkHeaderRe = regexp.MustCompile(`^@@ -\d+(,\d+)? \+\d+(,\d+)? @@`)
func headersValid(diff string) bool {
for _, line := range strings.Split(diff, "\n") {
if strings.HasPrefix(line, "@@") && !hunkHeaderRe.MatchString(line) {
return false
}
}
return true
} Try / catch
if _, _, err := ApplyUnifiedDiff(ctx, path, diff); err != nil {
var badHeader string
if m := regexp.MustCompile(`invalid hunk header: "([^"]*)"`).FindStringSubmatch(err.Error()); m != nil {
badHeader = m[1] // surface to user/regeneration prompt
}
return fmt.Errorf("diff rejected (bad header %q): %w", badHeader, err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- diff contains no hunks (no "@@ ... @@" header found)
- invalid hunk header %q: %w
- invalid diff line (must start with ' ', '-', or '+'): %q
- hunk %q has no content lines
- failed to apply diff to %s: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/5aa9aac2ba35a075.
Report an issue: GitHub.