golang/go · error

copying vet tool stdout: %w

Error message

copying vet tool stdout: %w

What it means

copyToStdout copies a reader (typically the vet tool's stdout) to os.Stdout while holding stdoutMu, which serializes concurrent JSON writes to stdout. If io.Copy fails - usually a broken pipe or I/O error - this wraps the cause. The lock prevents interleaved output from parallel vet actions.

Source

Thrown at src/cmd/go/internal/work/exec.go:1780

		defer f.Close() // ignore error
		if err := VetHandleStdout(f); err != nil {
			return err
		}
		f.Seek(0, io.SeekStart)           // ignore error
		cache.Default().Put(stdoutKey, f) // ignore error
	}

	return nil
}

var stdoutMu sync.Mutex // serializes concurrent writes (of e.g. JSON values) to stdout

// copyToStdout copies the stream to stdout while holding the lock.
func copyToStdout(r io.Reader) error {
	stdoutMu.Lock()
	defer stdoutMu.Unlock()
	if _, err := io.Copy(os.Stdout, r); err != nil {
		return fmt.Errorf("copying vet tool stdout: %w", err)
	}
	return nil
}

// linkActionID computes the action ID for a link action.
func (b *Builder) linkActionID(a *Action) cache.ActionID {
	p := a.Package
	h := cache.NewHash("link " + p.ImportPath)

	// Toolchain-independent configuration.
	fmt.Fprintf(h, "link\n")
	// Hash the resolved buildmode (ldBuildmode), not cfg.BuildBuildmode,
	// so that -buildmode=default produces the same build ID as the
	// buildmode it resolves to. See go.dev/issue/63559.
	fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", ldBuildmode, cfg.Goos, cfg.Goarch)
	fmt.Fprintf(h, "import %q\n", p.ImportPath)
	fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
	fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. If piping to head/less the error is expected and harmless - ignore it
  2. If redirecting to a file, confirm the destination is writable and has space
  3. Run go vet without a pipe to see if the error persists

Example fix

// before (broken pipe from head)
go vet ./... | head -5
// after
go vet ./... 2>&1 | head -5 || true
Defensive patterns

Strategy: try-catch

Try / catch

// When piping go output, tolerate SIGPIPE / broken pipe
out, err := cmd.CombinedOutput()
if err != nil && !errors.Is(err, syscall.EPIPE) {
    return err
}

Prevention

When it happens

Trigger: Fires in copyToStdout when io.Copy(os.Stdout, r) returns an error, while streaming vet/build tool output to the terminal or a pipe.

Common situations: Piping `go vet` to a consumer that exits early (head, less), closing the terminal mid-build, redirecting to a full disk, or any downstream reader closing its stdin.

Related errors


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