vxcontrol/pentagi · error

hunk %q has no content lines

Error message

hunk %q has no content lines

What it means

A hunk header was found but zero body lines followed it before the next header or end of input. A '@@ ... @@' line must be followed by at least one content line; an empty hunk is rejected because it would produce a no-op or malformed patch.

Source

Thrown at backend/pkg/tools/file_diff.go:110

			if strings.HasPrefix(line, `\`) {
				// e.g. "\ No newline at end of file" - not a content line.
				continue
			}
			if line == "" {
				hunk.lines = append(hunk.lines, diffHunkLine{sign: ' ', text: ""})
				continue
			}

			sign := line[0]
			if sign != ' ' && sign != '-' && sign != '+' {
				return nil, fmt.Errorf("invalid diff line (must start with ' ', '-', or '+'): %q", line)
			}
			hunk.lines = append(hunk.lines, diffHunkLine{sign: sign, text: line[1:]})
		}

		if len(hunk.lines) == 0 {
			return nil, fmt.Errorf("hunk %q has no content lines", header)
		}
		hunks = append(hunks, hunk)
	}

	return hunks, nil
}

// buildLineOffsets returns, for content, the byte offset at which each
// 1-based line begins: offsets[0] is the (always 0) offset of line 1,
// offsets[1] of line 2, and so on.
func buildLineOffsets(content string) []int {
	offsets := make([]int, 1, strings.Count(content, "\n")+1)
	offsets[0] = 0
	for i := 0; i < len(content); i++ {
		if content[i] == '\n' {
			offsets = append(offsets, i+1)
		}
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Ensure each hunk header in the diff is followed by at least one context/addition/removal line.
  2. Remove stray headers that have no associated body (usually leftover from a generator bug).
  3. Check any post-processing (trimming, filtering) that may have dropped the body lines.
  4. If the change is genuinely empty, do not emit a diff at all.

Example fix

// before
"@@ -1,1 +1,1 @@\n@@ -2,1 +2,1 @@\n-old\n+new"

// after
"@@ -1,1 +1,1 @@\n-old\n+new\n@@ -2,1 +2,1 @@\n context\n+added"
Defensive patterns

Strategy: validation

Validate before calling

func hunksHaveBody(diff string) bool {
	headers := 0
	bodyAfterLastHeader := false
	for _, line := range strings.Split(diff, "\n") {
		if strings.HasPrefix(line, "@@") {
			if headers > 0 && !bodyAfterLastHeader { return false }
			headers++; bodyAfterLastHeader = false
		} else if headers > 0 && strings.ContainsAny(line[:min(1, len(line))+0], " -+") {
			bodyAfterLastHeader = true
		}
	}
	return headers == 0 || bodyAfterLastHeader
}

Try / catch

if _, _, err := ApplyUnifiedDiff(ctx, path, diff); err != nil {
	if strings.Contains(err.Error(), "has no content lines") {
		// drop the empty hunk and re-apply the remainder
	}
	return err
}

Prevention

When it happens

Trigger: A diff contains '@@ -5,7 +5,8 @@' immediately followed by another hunk header, EOF, or blank separator lines only — e.g. tooling that emits headers in a loop but never appends the body.

Common situations: Custom scripts that build diffs header-by-header but break on body collection; diffs where all body lines were stripped by whitespace-trimming post-processing; empty diffs for files whose only change was mode bits.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/465fbcb233e1575b. Report an issue: GitHub.