Home / Alt manpages / go-fix(1)

  • go-fix(1)
  • User command
  • linux

Preview and Apply Go API Fixes with go fix

go fix rewrites source code to match newer APIs, and running it against a dirty tree is how a "quick modernisation" turns into an unreviewable diff. This guide finds the changes your installed toolchain proposes, reviews them as a patch, and only applies them once the package still builds and the diff makes sense. The examples use Go 1.26.1 from /home/linuxbrew/.linuxbrew/bin/go. The Debian golang-go package installed here is version 2:1.22~2build1, but its manual page documents an older interface, so check the actual go binary on your PATH before relying on a flag.

Allow about fifteen minutes for a small module, plus review time for a large repository. You need a Go module, a clean working tree, and a shell. The commands below do not need sudo.

Warning

Do not run this against a valuable tree until you have a commit or another verified backup. go fix changes source files, and the operation has no built-in undo command.

1. Check which Go tool you will run

The command name is not enough when several Go installations are present. Check its path, version, and current help:

$ command -v go
/home/linuxbrew/.linuxbrew/bin/go
$ go version
go version go1.26.1 linux/amd64
$ go help fix

On current Go, the documented shape is go fix [build flags] [-fixtool prog] [fix flags] [packages]. The local go-fix(1) page instead describes a -fix list passed to go tool fix -r. That difference matters: do not copy flags from the manpage blindly when the binary reports a newer command contract. Treat go help fix as the contract for the executable you are about to use.

Checkpoint

Record the version in your change review. If go help fix does not show -diff, stop and read that version's help before continuing.

2. Start from a recoverable working tree

Inspect the repository before allowing a source rewrite:

$ git status --short
$ git diff --check

An empty status is the clearest starting point. If you already have work in progress, commit it or use a separate worktree. This is a safety boundary rather than a requirement go fix imposes itself: a mixed diff makes it hard to tell which lines the tool changed, and that makes recovery easy to get wrong.

Warning

Do not treat go fix as a formatting-only command. Its registered analyzers can modernise APIs, rewrite loop code, change build directives, and apply source-level fix directives. Review every resulting file.

3. List the fixers before selecting one

Ask the tool which fixers it has installed:

$ go tool fix help
Registered analyzers:

    any          replace interface{} with any
    buildtag     check //go:build and // +build directives
    ...
    stringscutprefix replace HasPrefix/TrimPrefix with CutPrefix
    ...

The list is version-specific. On Go 1.26.1, the default suite includes fixers such as newexpr, rangeint, stringscutprefix, and waitgroup. Ask for one fixer's detail when you need to understand its scope:

$ go tool fix help stringscutprefix

Some older documentation calls these items fixes or rewrite rules. Current Go presents them as analysis-based fixers. The practical rule stays the same either way: read the installed description, because a fixer added in a later release will not exist in an older toolchain.

4. Preview the whole package selection

Run the preview from the module root. ./... means all packages below the current module path that the Go command can resolve:

$ go fix -diff ./...
--- /path/to/project/file.go (old)
+++ /path/to/project/file.go (new)
@@
-        message = strings.TrimPrefix(message, "he")
+        message = after

With the installed Go 1.26.1 command, -diff prints a unified diff and leaves the files unchanged. An empty output means this run found no applicable changes; it does not prove the code is correct, or that every desired API migration is available, only what this tool run would change.

Checkpoint

Save or review the preview before applying it:

$ go fix -diff ./... > /tmp/project-go-fix.patch
$ sed -n '1,160p' /tmp/project-go-fix.patch

The temporary patch is optional and contains source text, so do not leave confidential code sitting in a shared temporary directory. Remove it after review with rm -- /tmp/project-go-fix.patch once you are sure it is no longer useful.

5. Narrow the scope when the diff is too broad

A package pattern is part of the operation, not a comment for the reader. To inspect one package, use its module-relative path:

$ go fix -diff ./internal/parser

To use one named fixer while keeping the command's other fix flags, pass its analyser flag after go fix:

$ go fix -diff -stringscutprefix ./internal/parser

Check the installed help for the exact flag name and whether it is enabled by default. A fixer flag is not an API compatibility switch: it does not make code targeting an older Go release safe to change without testing the module's declared Go version and supported toolchains.

For a repository with generated code, vendored code, or several modules, inspect the package list first with go list ./.... Exclude paths deliberately rather than relying on a shell glob that happens to omit them.

6. Apply only an understood diff

Once the preview is acceptable and the working tree is clean, apply the same package selection:

$ go fix ./...
$ git diff --stat
$ git diff --check

There is normally no success message. The changed files and the Git diff are the output. The safest recovery path is to inspect the diff, run the project's tests, and then either commit it as a focused change or discard the whole thing with your normal version-control workflow.

Recovery

If you created a commit immediately before the operation, git revert COMMIT_ID is a recoverable undo for that commit. Do not use a broad reset when the tree holds work you have not backed up.

Run the project's normal checks after applying fixes:

$ go test ./...
$ go vet ./...

These commands check different things. A successful go fix run only means the suggested edits were applied; it is not a replacement for compilation, tests, review, or compatibility testing on the oldest Go version you support.

Common traps

  • Empty preview. Check the Go version, module root, package pattern, and fixer list. The current suite may simply have no applicable edits.
  • Package fails to load. Resolve the module or build-constraint error before trying to interpret fixer output.
  • Rejected flag. Run go help fix and go tool fix help again. The installed manpage may describe a different generation of the command, and an online example may target a newer release.
  • Generated files touched. Verify how the project regenerates them before committing either the generated result or the source change.
  • Using it to force a build to pass. go fix applies registered safe transformations, not arbitrary dependency upgrades or semantic migrations. Changes needing design decisions belong in a separate, deliberate edit, tested on its own.

Done means

  • Toolchain recorded: you noted the actual go binary and version.
  • Clean start: the working tree was clean, or existing work was safely separated first.
  • Fixers reviewed: you listed the installed fixers and previewed the exact package selection.
  • Diff understood: the applied diff contains only changes you actually understand.
  • Checks pass: go test ./..., go vet ./..., and the project's review checks all pass.
  • Backup exists: you have a commit or backup that can restore the pre-fix source.