{"record":{"id":"478584be8d396de1","repo":"vxcontrol/pentagi","slug":"diff-contains-no-hunks-no-header-foun","errorCode":null,"errorMessage":"diff contains no hunks (no \"@@ ... @@\" header found)","messagePattern":"diff contains no hunks \\(no \"@@ \\.\\.\\. @@\" header found\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/file_diff.go","lineNumber":68,"sourceCode":"// separate argument), \"\\ No newline at end of file\" markers, and a fully\n// blank line standing in for a one-space (empty) context line.\nfunc parseUnifiedDiff(diffText string) ([]diffHunk, error) {\n\tnormalized := strings.TrimSuffix(strings.ReplaceAll(diffText, \"\\r\\n\", \"\\n\"), \"\\n\")\n\tif normalized == \"\" {\n\t\treturn nil, fmt.Errorf(\"diff is empty\")\n\t}\n\tlines := strings.Split(normalized, \"\\n\")\n\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}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/file_diff.go#L50-L86","documentation":"parseUnifiedDiff in backend/pkg/tools/file_diff.go scans a unified diff for the first '@@ ... @@' hunk header. If it consumes the entire input without finding one, it reports that the diff contains no hunks. The tool requires a well-formed unified diff; input like 'old file text' or a plain English description of the edit is not accepted.","triggerScenarios":"ApplyUnifiedDiff or EditFile called with a diff string that has no '@@ -a,b +c,d @@' header at all — e.g. an empty string, a natural-language description of the change, plain search/replace text, or a header-only diff whose lines after ---/+++ are not hunk headers.","commonSituations":"An LLM agent returns a prose description or a '```diff' block that is actually empty; user pastes only the file-portion (---/+++) of a git diff; a template generated an empty diff when content was unchanged; diff output got truncated before the first hunk.","solutions":["Inspect the diff string passed to ApplyUnifiedDiff and ensure it contains at least one '@@ -old +new @@' hunk header after the optional ---/+++ file headers.","If the diff is produced by another tool or LLM, ask it to regenerate as a proper unified diff (git diff format) with hunk headers.","Check the input is not empty or truncated (log its length and first lines before calling ApplyUnifiedDiff).","If no change is actually needed, skip calling ApplyUnifiedDiff entirely instead of passing an empty diff."],"exampleFix":"// before\nApplyUnifiedDiff(ctx, path, \"--- a/f.txt\\n+++ b/f.txt\")\n\n// after\nApplyUnifiedDiff(ctx, path, \"--- a/f.txt\\n+++ b/f.txt\\n@@ -1,1 +1,2 @@\\n old line\\n+new line\")","handlingStrategy":"validation","validationCode":"func hasHunkHeader(diff string) bool {\n\treturn strings.Contains(diff, \"@@\") && regexp.MustCompile(`(?m)^@@ -\\d+(,\\d+)? \\+\\d+(,\\d+)? @@`).MatchString(diff)\n}\n// call ApplyUnifiedDiff only if hasHunkHeader(diff) && strings.TrimSpace(diff) != \"\"","typeGuard":null,"tryCatchPattern":"newContent, n, err := ApplyUnifiedDiff(ctx, path, diff)\nif err != nil {\n\tif strings.Contains(err.Error(), \"no hunks\") {\n\t\t// treat as no-op or regenerate a proper unified diff\n\t}\n\treturn err\n}","preventionTips":["Always generate diffs with a real tool (git diff -U3) instead of hand-writing them","Log the first lines of the diff before applying to catch empty/truncated input early","Reject empty diffs at the call site instead of passing them to the applier","In LLM pipelines, include a unified-diff format example in the prompt/schema"],"tags":["diff","parsing","unified-diff","input-validation"],"backgroundTag":"malformed-unified-diff","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}