{"record":{"id":"465fbcb233e1575b","repo":"vxcontrol/pentagi","slug":"hunk-q-has-no-content-lines","errorCode":null,"errorMessage":"hunk %q has no content lines","messagePattern":"hunk %q has no content lines","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/file_diff.go","lineNumber":110,"sourceCode":"\n\t\t\tif strings.HasPrefix(line, `\\`) {\n\t\t\t\t// e.g. \"\\ No newline at end of file\" - not a content line.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif line == \"\" {\n\t\t\t\thunk.lines = append(hunk.lines, diffHunkLine{sign: ' ', text: \"\"})\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsign := line[0]\n\t\t\tif sign != ' ' && sign != '-' && sign != '+' {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid diff line (must start with ' ', '-', or '+'): %q\", line)\n\t\t\t}\n\t\t\thunk.lines = append(hunk.lines, diffHunkLine{sign: sign, text: line[1:]})\n\t\t}\n\n\t\tif len(hunk.lines) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"hunk %q has no content lines\", header)\n\t\t}\n\t\thunks = append(hunks, hunk)\n\t}\n\n\treturn hunks, nil\n}\n\n// buildLineOffsets returns, for content, the byte offset at which each\n// 1-based line begins: offsets[0] is the (always 0) offset of line 1,\n// offsets[1] of line 2, and so on.\nfunc buildLineOffsets(content string) []int {\n\toffsets := make([]int, 1, strings.Count(content, \"\\n\")+1)\n\toffsets[0] = 0\n\tfor i := 0; i < len(content); i++ {\n\t\tif content[i] == '\\n' {\n\t\t\toffsets = append(offsets, i+1)\n\t\t}\n\t}","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/file_diff.go#L92-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure each hunk header in the diff is followed by at least one context/addition/removal line.","Remove stray headers that have no associated body (usually leftover from a generator bug).","Check any post-processing (trimming, filtering) that may have dropped the body lines.","If the change is genuinely empty, do not emit a diff at all."],"exampleFix":"// before\n\"@@ -1,1 +1,1 @@\\n@@ -2,1 +2,1 @@\\n-old\\n+new\"\n\n// after\n\"@@ -1,1 +1,1 @@\\n-old\\n+new\\n@@ -2,1 +2,1 @@\\n context\\n+added\"","handlingStrategy":"validation","validationCode":"func hunksHaveBody(diff string) bool {\n\theaders := 0\n\tbodyAfterLastHeader := false\n\tfor _, line := range strings.Split(diff, \"\\n\") {\n\t\tif strings.HasPrefix(line, \"@@\") {\n\t\t\tif headers > 0 && !bodyAfterLastHeader { return false }\n\t\t\theaders++; bodyAfterLastHeader = false\n\t\t} else if headers > 0 && strings.ContainsAny(line[:min(1, len(line))+0], \" -+\") {\n\t\t\tbodyAfterLastHeader = true\n\t\t}\n\t}\n\treturn headers == 0 || bodyAfterLastHeader\n}","typeGuard":null,"tryCatchPattern":"if _, _, err := ApplyUnifiedDiff(ctx, path, diff); err != nil {\n\tif strings.Contains(err.Error(), \"has no content lines\") {\n\t\t// drop the empty hunk and re-apply the remainder\n\t}\n\treturn err\n}","preventionTips":["In diff generators, always append the collected body immediately after each header","Filter out hunks with zero body lines before applying","Audit post-processing steps that filter or trim diff lines"],"tags":["diff","parsing","unified-diff","empty-hunk"],"backgroundTag":"invalid-diff-line","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}