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
- If piping to head/less the error is expected and harmless - ignore it
- If redirecting to a file, confirm the destination is writable and has space
- 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
- Avoid piping go vet/build into tools that close stdin early (head without -q)
- Redirect to a file when capturing large outputs
- In CI, set stdout to a file or /dev/null rather than a pipe that may close
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
- reading srcfiles list: %w
- %s: wrong signature for %s, %s
- copying diff output: %w
- loading cached file %s: %w
- finding %s: %w
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/50fd5490255cb566.
Report an issue: GitHub.