golangci/golangci-lint · error
%q suggests invalid fix: pos (%v) > end (%v)
Error message
%q suggests invalid fix: pos (%v) > end (%v)
What it means
The fixer applies SuggestedFixes from linters, and each text edit must have Pos <= End. When a linter emits a suggested fix whose start position is after its end position, the fixer rejects the whole run's fixes with this error naming the linter. It guards against corrupting files with inverted edit ranges.
Source
Thrown at pkg/result/processors/fixer.go:106
for i := range issues {
issue := issues[i]
if slices.Contains(formatters, issue.FromLinter) {
toBeFormattedFiles[issue.FilePath()] = struct{}{}
continue
}
if issue.SuggestedFixes == nil || skipNoTextEdit(issue) {
notFixableIssues = append(notFixableIssues, issue)
continue
}
for _, sf := range issue.SuggestedFixes {
for _, edit := range sf.TextEdits {
start, end := edit.Pos, edit.End
if start > end {
return nil, fmt.Errorf("%q suggests invalid fix: pos (%v) > end (%v)",
issue.FromLinter, edit.Pos, edit.End)
}
edit := diff.Edit{
Start: int(start),
End: int(end),
New: string(edit.NewText),
}
if _, ok := editsByLinter[issue.FilePath()]; !ok {
editsByLinter[issue.FilePath()] = make(map[string][]diff.Edit)
}
editsByLinter[issue.FilePath()][issue.FromLinter] = append(editsByLinter[issue.FilePath()][issue.FromLinter], edit)
}
}
}
View on GitHub (pinned to ed7a235d2d)
Solutions
- Update (or pin) the offending linter named in the error to a version with fixed position computation
- Disable the linter's fixer for that linter (e.g. run without --fix or exclude the linter) until fixed
- Report the bug to the linter maintainer with the failing file/linter name
- Verify file/position data isn't being transformed between analysis and fixing in custom plugins
Example fix
// before (custom linter)
edit := analysis.TextEdit{Pos: end, End: start}
// after
if start > end { start, end = end, start }
edit := analysis.TextEdit{Pos: start, End: end} Defensive patterns
Strategy: validation
Validate before calling
// Go: sanity-check text edits before emitting a SuggestedFix from a custom linter
func validEdit(e analysis.TextEdit) bool { return e.Pos <= e.End }
if !validEdit(edit) { return nil, fmt.Errorf("invalid edit range %d..%d", edit.Pos, edit.End) } Try / catch
fixed, err := fixer.Process(issues)
if err != nil {
if strings.Contains(err.Error(), "suggests invalid fix") {
log.Fatalf("linter emitted bad fix: %v", err)
}
return err
} Prevention
- Keep linter versions in sync with the golangci-lint go/analysis version
- Test custom analyzers' suggested fixes against go/analysis's own sanity checks
- Avoid mutating positions (e.g. via token.File offsets) after prior edits
When it happens
Trigger: process iterates issue.SuggestedFixes and encounters a TextEdit where edit.Pos > edit.End — produced by a buggy linter or an analyzer working with stale/incorrect position information.
Common situations: A custom or third-party linter computing token positions off-by-one; using a linter version incompatible with the golangci-lint go/analysis version; fixes generated from cached/rewritten file positions after edits.
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/5aed7e67b92d0fde.
Report an issue: GitHub.