golang/go · error

file content changed underfoot

Error message

file content changed underfoot

What it means

Raised while committing a cache output file: the writer reads the final byte, hashes the content, and compares to the expected OutputID before writing the byte that completes the expected size. A mismatch means the file was altered between the initial write and the commit — another process or external actor changed it. The cache truncates and returns this error to avoid publishing a corrupt entry.

Source

Thrown at src/cmd/go/internal/cache/cache.go:690

	h := sha256.New()
	w := io.MultiWriter(f, h)
	if _, err := io.CopyN(w, file, size-1); err != nil {
		f.Truncate(0)
		return err
	}
	// Check last byte before writing it; writing it will make the size match
	// what other processes expect to find and might cause them to start
	// using the file.
	buf := make([]byte, 1)
	if _, err := file.Read(buf); err != nil {
		f.Truncate(0)
		return err
	}
	h.Write(buf)
	sum := h.Sum(nil)
	if !bytes.Equal(sum, out[:]) {
		f.Truncate(0)
		return fmt.Errorf("file content changed underfoot")
	}

	// Commit cache file entry.
	if _, err := f.Write(buf); err != nil {
		f.Truncate(0)
		return err
	}
	if err := f.Close(); err != nil {
		// Data might not have been written,
		// but file may look like it is the right size.
		// To be extra careful, remove cached file.
		os.Remove(name)
		return err
	}
	os.Chtimes(name, c.now(), c.now()) // mainly for tests

	return nil
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Keep GOCACHE on a local per-machine filesystem; never share it across hosts.
  2. Give each machine/container its own GOCACHE directory.
  3. Run `go clean -cache` to flush possibly-corrupt entries and rebuild.
  4. Disable any process that scans/alters files under GOCACHE.

Example fix

// before: shared cache on a network FS
//   GOCACHE=/mnt/nfs/shared-go-build  -> file content changed underfoot
//
// after: per-machine local cache
$ GOCACHE=$HOME/.cache/go-build go build .
Defensive patterns

Strategy: fallback

Try / catch

err := c.PutOutput(...)
if err != nil && strings.Contains(err.Error(), "file content changed underfoot") {
    // shared/unsafe GOCACHE: fall back to a clean rebuild
    _ = os.RemoveAll(c.Dir)
    // retry the build without parallel cache writers

Prevention

When it happens

Trigger: Concurrent writers to the same cache entry racing on the same output ID; external modification of cache files between write and verify; unreliable shared filesystem (NFS/network FS) semantics. The package doc explicitly warns cross-machine sharing is unsafe.

Common situations: GOCACHE on a network mount shared across machines/containers; two go invocations racing on the same GOCACHE on a filesystem with weak locking; backup/AV scanners touching cache files.

Related errors


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