golang/go · error

updating go.mod

Error message

updating go.mod: %w

What it means

Generic wrapper emitted when the committed go.mod update transaction failed for any reason other than errNoChange. The original error (commonly error 1076, but also lock failures, I/O write errors) is wrapped with %w under 'updating go.mod:'. This is the user-facing top of the update error chain.

Solutions

  1. Unwrap the inner error to find the root cause (most often 1076 -> serialize commands).
  2. Ensure the module directory is writable and not locked by AV / IDE.
  3. Free disk space / inode quota if write failed due to ENOSPC.
  4. Re-run after resolving the root cause; the transaction is atomic so no partial write remains.

Example fix

// before
$ go build ./...
// updating go.mod: existing contents have changed since last read

// after (resolve the inner cause)
$ pkill -f 'go mod'   // stop the concurrent writer
$ go build ./...
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure go.mod is writable and not locked before building.
fi, err := os.Stat("go.mod")
if err != nil { return err }
if fi.Mode().Perm()&0200 == 0 {
    return errors.New("go.mod not writable; updates will fail")
}
// also ensure no other writer holds it (advisory lock check omitted for brevity)

Try / catch

out, err := exec.Command("go", "build", "./...").CombinedOutput()
if err != nil && bytes.Contains(out, []byte("updating go.mod:")) {
    // unwrap inner cause to route recovery
    inner := strings.TrimSpace(strings.TrimPrefix(string(out), "updating go.mod:"))
    switch {
    case strings.Contains(inner, "existing contents have changed"):
        // serialize and retry once
        out, err = exec.Command("go", "build", "./...").CombinedOutput()
    case strings.Contains(inner, "permission denied"):
        return fmt.Errorf("go.mod not writable: %s", inner)
    default:
        return fmt.Errorf("go.mod update failed: %s", inner)
    }
}
return err

Prevention

When it happens

Trigger: modload commits the go.mod rewrite closure and the returned err is non-nil and not errNoChange. Most often the inner error is 'existing contents have changed since last read' (1076); can also be fsync/write permission errors.

Common situations: Same as 1076 plus read-only filesystems, full disk, antivirus locking go.mod on Windows, or a held lock by another process.

Related errors


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

Appendix: source

Thrown at src/cmd/go/internal/modload/init.go:2099

			// other process.
			return nil, errNoChange
		}

		if index != nil && !bytes.Equal(old, index.data) {
			// The contents of the go.mod file have changed. In theory we could add all
			// of the new modules to the build list, recompute, and check whether any
			// module in *our* build list got bumped to a different version, but that's
			// a lot of work for marginal benefit. Instead, fail the command: if users
			// want to run concurrent commands, they need to start with a complete,
			// consistent module definition.
			return nil, fmt.Errorf("existing contents have changed since last read")
		}

		return updatedGoMod, nil
	})

	if err != nil && err != errNoChange {
		return fmt.Errorf("updating go.mod: %w", err)
	}
	return nil
}

// keepSums returns the set of modules (and go.mod file entries) for which
// checksums would be needed in order to reload the same set of packages
// loaded by the most recent call to LoadPackages or ImportFromFiles,
// including any go.mod files needed to reconstruct the MVS result
// or identify go versions,
// in addition to the checksums for every module in keepMods.
func keepSums(ld *Loader, ctx context.Context, pld *packageLoader, rs *Requirements, which whichSums) map[module.Version]bool {
	// Every module in the full module graph contributes its requirements,
	// so in order to ensure that the build list itself is reproducible,
	// we need sums for every go.mod in the graph (regardless of whether
	// that version is selected).
	keep := make(map[module.Version]bool)

	// Add entries for modules in the build list with paths that are prefixes of

View on GitHub (pinned to b6b368adc5)