golang/go · error

%s loaded from %v, but go %s would select %v

Error message

%s loaded from %v,
	but go %s would select %v

What it means

Emitted by 'go mod tidy' compatibility check when a package loads successfully under both the current and the -compat Go versions, but from different modules (pkg.mod != mismatch.mod). The toolchain flags this because builds could silently vary in behavior depending on which Go version compiles them.

Source

Thrown at src/cmd/go/internal/modload/load.go:2254

			// unpruned graph due to a newer-than-latest dependency that is normally
			// pruned out.
			//
			// This could also occur if the source code for the module providing the
			// package in the pruned graph has a checksum error, but the unpruned
			// graph upgrades that module to a version with a correct checksum.
			//
			// pkg.err should have already been logged elsewhere — along with a
			// stack trace — so log only the import path and non-error info here.
			suggestUpgrade = true
			pld.error(fmt.Errorf("%s failed to load from any module,\n\tbut go %s would load it from %v", pkg.path, compatVersion, mismatch.mod))

		case pkg.mod != mismatch.mod:
			// The package is loaded successfully by both Go versions, but from a
			// different module in each. This could lead to subtle (and perhaps even
			// unnoticed!) variations in behavior between builds with different
			// toolchains.
			suggestUpgrade = true
			pld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, compatVersion, mismatch.mod.Version))

		default:
			base.Fatalf("go: internal error: mismatch recorded for package %s, but no differences found", pkg.path)
		}
	}

	pld.switchIfErrors(ctx)
	suggestFixes()
	pld.exitIfErrors(ctx)
}

// scanDir is like imports.ScanDir but elides known magic imports from the list,
// so that we do not go looking for packages that don't really exist.
//
// The standard magic import is "C", for cgo.
//
// The only other known magic imports are appengine and appengine/*.
// These are so old that they predate "go get" and did not use URL-like paths.

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Run the suggested upgrade path: 'go mod tidy -go=<compatVersion> && go mod tidy' so both graphs agree.
  2. Add an explicit 'require' (and, if needed, a 'replace') that pins the module you want both toolchains to select.
  3. If only the current toolchain matters, re-run 'go mod tidy -compat=<yourGoVersion>'.
  4. Verify no competing 'replace' directives or vendored modules are causing the divergence with 'go list -m all'.

Example fix

// before
$ go mod tidy
// error: example.com/pkg loaded from example.com/mod@v1.2.0,
// 	but go 1.20 would select v1.5.0

// after: align the selection
$ go get example.com/mod@v1.5.0 && go mod tidy
Defensive patterns

Strategy: validation

Validate before calling

// Ensure both toolchains select the same module for each import:
//   diff <(GOFLAGS=-mod=mod go list -m all) <(go list -m all)
// Any difference in the module providing a package is a divergence to resolve with an explicit require/replace.

Prevention

When it happens

Trigger: Running 'go mod tidy' where the pruned graph resolves an import to one module while the older unpruned graph selects a different module for the same import path — e.g. a package moved between two modules in the same project, or a fork and upstream both provide the path.

Common situations: A multi-module repository split a package into a new module; a 'replace' directive affects one toolchain's resolution but not the other; an 'incompatible' (+incompatible) version vs. a properly versioned v2+ module both provide the path.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/e45cbf450939b0b3. Report an issue: GitHub.