golang/go · error

%s cannot be modified

Error message

%s cannot be modified

What it means

Returned by checkEnvWrite when `go env -w KEY=VAL` targets one of the read-only, computed variables: GOEXE, GOGCCFLAGS, GOHOSTARCH, GOHOSTOS, GOMOD, GOROOT, GOTELEMETRY, GOTELEMETRYDIR, GOTOOLDIR, GOVERSION, GOWORK. These reflect the active toolchain/session state, so the go command refuses to persist them into the go-env config file.

Source

Thrown at src/cmd/go/internal/envcmd/env.go:645

		}
	}
	return ""
}

func checkEnvWrite(key, val string) error {
	switch key {
	case "GOEXE",
		"GOGCCFLAGS",
		"GOHOSTARCH",
		"GOHOSTOS",
		"GOMOD",
		"GOROOT",
		"GOTELEMETRY",
		"GOTELEMETRYDIR",
		"GOTOOLDIR",
		"GOVERSION",
		"GOWORK":
		return fmt.Errorf("%s cannot be modified", key)
	case "GOENV", "GODEBUG":
		return fmt.Errorf("%s can only be set using the OS environment", key)
	}

	// To catch typos and the like, check that we know the variable.
	// If it's already in the env file, we assume it's known.
	if !cfg.CanGetenv(key) {
		return fmt.Errorf("unknown go command variable %s", key)
	}

	// Some variables can only have one of a few valid values. If set to an
	// invalid value, the next cmd/go invocation might fail immediately,
	// even 'go env -w' itself.
	switch key {
	case "GO111MODULE":
		switch val {
		case "", "auto", "on", "off":
		default:

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Set the variable in the OS environment (export GOROOT=...; or in the parent process env) rather than via `go env -w`.
  2. For GOROOT specifically: install/use the desired Go toolchain (e.g. via go toolchain directives or GOTOOLCHAIN) instead of rewriting GOROOT.
  3. Pick the correct user-settable equivalent — consult `go help environment` for the writable var list.
  4. Remove the offending line from your setup script that calls `go env -w` on a computed key.

Example fix

# before
$ go env -w GOROOT=/opt/go-beta
error: GOROOT cannot be modified
# after — set it in the shell/CI environment instead
$ GOROOT=/opt/go-beta go build ./...
Defensive patterns

Strategy: validation

Validate before calling

// Reject read-only keys before calling `go env -w`.
var readOnly = map[string]bool{
    "GOEXE": true, "GOGCCFLAGS": true, "GOHOSTARCH": true,
    "GOHOSTOS": true, "GOMOD": true, "GOROOT": true,
    "GOTELEMETRY": true, "GOTELEMETRYDIR": true, "GOTOOLDIR": true,
    "GOVERSION": true, "GOWORK": true,
}
func safeEnvW(key, val string) error {
    if readOnly[key] {
        return fmt.Errorf("%s cannot be set via `go env -w`; use OS env", key)
    }
    return runGoEnvW(key, val)
}

Prevention

When it happens

Trigger: Invoking `go env -w GOROOT=/custom/go`, `go env -w GOVERSION=...`, `go env -w GOMOD=...`, or any other listed key in checkEnvWrite's first switch case.

Common situations: Scripts trying to relocate GOROOT via `go env -w` instead of reinstalling or setting GOROOT in the OS environment; CI images attempting to pin GOVERSION; users confused between build-computed vars and user-settable ones.

Related errors


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