vxcontrol/pentagi · error

invalid diff line (must start with ' ', '-', or '+'): %q

Error message

invalid diff line (must start with ' ', '-', or '+'): %q

What it means

Within a hunk, every body line must begin with ' ' (context), '-' (removal), or '+' (addition). parseUnifiedDiff rejects any other first character. This catches diffs using '\ No newline at end of file' incorrectly placed, '!' markers from context diffs, or lines missing their leading space.

Source

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

		}
		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.
				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)

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the quoted line in the error and ensure it begins with exactly one of ' ', '-', or '+'.
  2. Re-add stripped leading spaces on context lines — every unchanged line needs a single leading space.
  3. Regenerate the diff in unified format (git diff, diff -u) instead of context or other formats.
  4. Avoid channels that collapse whitespace (chat markdown, email) when moving diffs; use files or base64.

Example fix

// before (context line lost its leading space)
"unchanged line"

// after
" unchanged line"
Defensive patterns

Strategy: validation

Validate before calling

func hunkBodyValid(diff string) bool {
	inHunk := false
	for _, line := range strings.Split(diff, "\n") {
		if strings.HasPrefix(line, "@@") { inHunk = true; continue }
		if inHunk && line != "" && !strings.ContainsAny(line[:1], " -+") {
			return false
		}
	}
	return true
}

Try / catch

if err := tryApply(diff); err != nil {
	if strings.Contains(err.Error(), "invalid diff line") {
		diff = repairLeadingWhitespace(diff) // re-add missing leading space on context lines
		return tryApply(diff)
	}
	return err
}

Prevention

When it happens

Trigger: A hunk body line starts with a character other than ' ', '-', '+' — e.g. a context line whose leading space was stripped by an editor or chat formatting, a '!'/'*' context-diff marker, or a line beginning with '\\' inside the hunk.

Common situations: Markdown/chat pipelines strip leading whitespace from diff lines, turning context lines into invalid lines; tools emit context-format diffs instead of unified; copying diffs from terminals where the leading space is invisible and gets lost.

Related errors


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