golang/go · error

%s: argument must be a clean package path

Error message

%s: argument must be a clean package path

What it means

Thrown by the Go command's package@version install workflow (e.g. `go install pkg@v1.0.0`). After stripping the `@version` suffix, the remaining path `p` is rejected when `pathpkg.Clean(p) != p`, i.e. the path is not in canonical form. The command requires a clean import path because non-canonical forms (redundant slashes, stray `.`/`..` segments) make module resolution ambiguous.

Source

Thrown at src/cmd/go/internal/load/pkg.go:3411

			}
			break
		}
	}
	patterns := make([]string, len(args))
	for i, arg := range args {
		p, found := strings.CutSuffix(arg, "@"+version)
		if !found {
			return nil, fmt.Errorf("%s: all arguments must refer to packages in the same module at the same version (@%s)", arg, version)
		}
		switch {
		case build.IsLocalImport(p):
			return nil, fmt.Errorf("%s: argument must be a package path, not a relative path", arg)
		case filepath.IsAbs(p):
			return nil, fmt.Errorf("%s: argument must be a package path, not an absolute path", arg)
		case search.IsMetaPackage(p):
			return nil, fmt.Errorf("%s: argument must be a package path, not a meta-package", arg)
		case pathpkg.Clean(p) != p:
			return nil, fmt.Errorf("%s: argument must be a clean package path", arg)
		case !strings.Contains(p, "...") && search.IsStandardImportPath(p) && modindex.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, p):
			return nil, fmt.Errorf("%s: argument must not be a package in the standard library", arg)
		default:
			patterns[i] = p
		}
	}
	patterns = search.CleanPatterns(patterns)

	// Query the module providing the first argument, load its go.mod file, and
	// check that it doesn't contain directives that would cause it to be
	// interpreted differently if it were the main module.
	//
	// If multiple modules match the first argument, accept the longest match
	// (first result). It's possible this module won't provide packages named by
	// later arguments, and other modules would. Let's not try to be too
	// magical though.
	allowed := ld.CheckAllowed
	if modload.IsRevisionQuery(firstPath, version) {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Remove redundant `/`, leading/trailing separators, and `.`/`..` segments from the path portion before `@version`.
  2. If constructing the argument in code, run `path.Clean(p)` and assert it equals `p` before appending `@version`.
  3. Use the canonical module root path exactly as it appears in the module's go.mod `module` directive.

Example fix

// before
go install example.com/foo/../bar@v1.0.0

// after
go install example.com/bar@v1.0.0
Defensive patterns

Strategy: validation

Validate before calling

import "path"

func cleanPackageArg(p, version string) (string, error) {
    if path.Clean(p) != p {
        return "", fmt.Errorf("path %q is not clean; use %q", p, path.Clean(p))
    }
    return p + "@" + version, nil
}

Prevention

When it happens

Trigger: Running `go install` or `go get pkg@version` where the path portion contains double slashes, leading/trailing slashes, or `.`/`..` segments, e.g. `go install example.com/foo//bar@v1.0.0` or `go install example.com/./pkg@latest`.

Common situations: Copy-pasting a path with stray slashes; building the argument string programmatically without cleaning it; concatenating path fragments that introduce redundant separators.

Related errors


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