golang/go · error
non-canonical module version %q
Error message
non-canonical module version %q
What it means
Thrown by `modfetch.CachePath` when the module version passes `ModIsValid` but `module.CanonicalVersion(version) != version`. Canonical versions have no redundant components (e.g., 'v1.2.0' not 'v1.2', no '+build' metadata that's identical to base). The cache requires canonical versions so every module has exactly one cache location.
Source
Thrown at src/cmd/go/internal/modfetch/cache.go:60
if err != nil {
return "", err
}
return filepath.Join(cfg.GOMODCACHE, "cache/download", enc, "/@v"), nil
}
func CachePath(ctx context.Context, m module.Version, suffix string) (string, error) {
if gover.IsToolchain(m.Path) {
return "", ErrToolchain
}
dir, err := cacheDir(ctx, m.Path)
if err != nil {
return "", err
}
if !gover.ModIsValid(m.Path, m.Version) {
return "", fmt.Errorf("non-semver module version %q", m.Version)
}
if module.CanonicalVersion(m.Version) != m.Version {
return "", fmt.Errorf("non-canonical module version %q", m.Version)
}
encVer, err := module.EscapeVersion(m.Version)
if err != nil {
return "", err
}
return filepath.Join(dir, encVer+"."+suffix), nil
}
// DownloadDir returns the directory to which m should have been downloaded.
// An error will be returned if the module path or version cannot be escaped.
// An error satisfying errors.Is(err, fs.ErrNotExist) will be returned
// along with the directory if the directory does not exist or if the directory
// is not completely populated.
func DownloadDir(ctx context.Context, m module.Version) (string, error) {
if gover.IsToolchain(m.Path) {
return "", ErrToolchain
}
if err := checkCacheDir(ctx); err != nil {View on GitHub (pinned to b6b368adc5)
Solutions
- Canonicalize the version before calling CachePath: `version = module.CanonicalVersion(version)`
- Use module.EscapeVersion which also expects canonical input — canonicalize upstream
- Validate with `module.CanonicalVersion(v) == v` before calling cache APIs
Example fix
// before
path, err := modfetch.CachePath(ctx, module.Version{Path: m, Version: "v1.2"}, "zip")
// after
canon := module.CanonicalVersion("v1.2")
path, err := modfetch.CachePath(ctx, module.Version{Path: m, Version: canon}, "zip") Defensive patterns
Strategy: validation
Validate before calling
import "golang.org/x/mod/module"
func canonicalizeVersion(v string) string {
return module.CanonicalVersion(v)
}
// Before calling CachePath:
v = module.CanonicalVersion(v)
if v != originalV {
// version was non-canonical, now fixed
} Prevention
- Always pass module.CanonicalVersion(v) to cache APIs
- Normalize version strings at the boundary where they enter your code
- Use versions returned by the module resolution pipeline, which are pre-canonicalized
When it happens
Trigger: Calling CachePath with a version like 'v1.2' (should be 'v1.2.0'), 'v1.0.0+meta' where the metadata is non-significant, or 'v1.00.0' (non-canonical zero-padding). CanonicalVersion normalizes these, and if the result differs, the error fires.
Common situations: Receiving non-canonical versions from external sources (proxies, manifests); user-supplied versions that aren't normalized; bugs in version string construction in calling code.
Related errors
- non-semver module version %q
- invalid version %q
- invalid version interval: %q
- expecting a Go version like %q
- maximum supported Go version is %s
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/e2b435d11eb19541.
Report an issue: GitHub.