{"record":{"id":"2e8bb1f344963792","repo":"micro-editor/micro","slug":"no-next-diff-hunk","errorCode":null,"errorMessage":"no next diff hunk","messagePattern":"no next diff hunk","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"internal/buffer/buffer.go","lineNumber":1447,"sourceCode":"\n// FindNextDiffLine returns the line number of the next block of diffs.\n// If `startLine` is already in a block of diffs, lines in that block are skipped.\nfunc (b *Buffer) FindNextDiffLine(startLine int, forward bool) (int, error) {\n\tif b.diff == nil {\n\t\treturn 0, errors.New(\"no diff data\")\n\t}\n\tstartStatus, ok := b.diff[startLine]\n\tif !ok {\n\t\tstartStatus = DSUnchanged\n\t}\n\tcurLine := startLine\n\tfor {\n\t\tcurStatus, ok := b.diff[curLine]\n\t\tif !ok {\n\t\t\tcurStatus = DSUnchanged\n\t\t}\n\t\tif curLine < 0 || curLine > b.LinesNum() {\n\t\t\treturn 0, errors.New(\"no next diff hunk\")\n\t\t}\n\t\tif curStatus != startStatus {\n\t\t\tif startStatus != DSUnchanged && curStatus == DSUnchanged {\n\t\t\t\t// Skip over the block of unchanged text\n\t\t\t\tstartStatus = DSUnchanged\n\t\t\t} else {\n\t\t\t\treturn curLine, nil\n\t\t\t}\n\t\t}\n\t\tif forward {\n\t\t\tcurLine++\n\t\t} else {\n\t\t\tcurLine--\n\t\t}\n\t}\n}\n\n// SearchMatch returns true if the given location is within a match of the last search.","sourceCodeStart":1429,"sourceCodeEnd":1465,"githubUrl":"https://github.com/micro-editor/micro/blob/1c8b82b32e408a5faf340039ed92d5266bea3293/internal/buffer/buffer.go#L1429-L1465","documentation":"Returned by (*Buffer).FindNextDiffLine (internal/buffer/buffer.go:1447) when the scan walks past the end of the buffer (curLine < 0 or > LinesNum()) without the diff status changing to a new hunk. In other words: from startLine in the given direction there is no further changed/unchanged boundary — you're already at the last (or first) diff hunk. It is a search-exhausted sentinel, not a fault.","triggerScenarios":"Cursor sits in/below the final changed hunk and NextDiff is invoked (forward scan hits EOF); or cursor is above the first hunk and PrevDiff is invoked (backward scan hits BOF). Emitted by the NextDiff/PrevDiff actions in internal/action/actions.go.","commonSituations":"Repeatedly pressing the next-diff binding to review changes and running one press past the last hunk; macros that loop diffs without an exit condition.","solutions":["Treat it as 'no more hunks': reverse direction (use PrevDiff) or jump back with > goto / undoline","Re-run > diff to refresh hunk positions if you believe changes exist beyond the cursor (stale diff state after edits)","In plugins, break the loop on this error rather than retrying"],"exampleFix":"// before\nfor {\n    l, err := h.Buf.FindNextDiffLine(cur, true)\n    cur = l // ignores err, loops forever at EOF\n}\n\n// after\nfor {\n    l, err := h.Buf.FindNextDiffLine(cur, true)\n    if err != nil { break } // no next diff hunk -> done\n    cur = l\n}","handlingStrategy":"try-catch","validationCode":"// Bound the search yourself so exhaustion is expected, not exceptional\nto := h.Buf.LinesNum()\nif forward && cur >= to-1 { /* nothing ahead: skip the call */ }\nif !forward && cur <= 0 { /* nothing behind: skip the call */ }\ndl, err := h.Buf.FindNextDiffLine(cur, forward)","typeGuard":null,"tryCatchPattern":"for {\n    l, err := h.Buf.FindNextDiffLine(cur, true)\n    if err != nil {\n        if err.Error() == \"no next diff hunk\" {\n            break // sentinel: reached last hunk in this direction — stop cleanly\n        }\n        return err // unexpected\n    }\n    cur = l\n}","preventionTips":["Treat 'no next diff hunk' as loop termination, never as an error to log loudly","Refresh with > diff after edits; hunks shift as you type","Alternate Next/Prev to walk back instead of probing past EOF repeatedly"],"tags":["diff","git","navigation","sentinel"],"backgroundTag":null,"analyzedSha":"1c8b82b32e408a5faf340039ed92d5266bea3293","analyzedAt":"2026-08-15T20:01:45.134Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}