JuliusBrussee/caveman · error
write stdout: %w
Error message
write stdout: %w
What it means
The engine CLI could not write the (pass-through) payload bytes to stdout. This is an environment-level pipe failure: the downstream reader closed the pipe, the terminal vanished, or a redirection target (file/disk) rejected the write. Because stdout is the clean payload channel, any write failure aborts emission.
Source
Thrown at engine/cmd/caveman-engine/main.go:133
}
// emitCompressResult preserves the engine's byte-safety contract at the CLI
// boundary. CCR failures are expected operational conditions: the engine has
// already returned an accounted pass-through result, so stdout must still get
// the original bytes. Any contradictory result fails rather than guessing.
func emitCompressResult(input []byte, res engine.Result, compressErr error, stdout, stderr io.Writer) error {
code := ""
if compressErr != nil {
if !bytes.Equal(res.Output, input) || !res.PassedThrough() || res.TokensAfter != res.TokensBefore {
return fmt.Errorf("unsafe recovery failure result: %w", compressErr)
}
code = "cave_ccr_unavailable"
if errors.Is(compressErr, ccr.ErrBudgetExceeded) {
code = "cave_ccr_budget_exceeded"
}
}
if _, err := stdout.Write(res.Output); err != nil {
return fmt.Errorf("write stdout: %w", err)
}
// Report stays on stderr so stdout remains clean payload bytes.
report, err := json.Marshal(compressReport{Result: res, Error: code})
if err != nil {
return fmt.Errorf("encode report: %w", err)
}
if _, err := fmt.Fprintln(stderr, string(report)); err != nil {
return fmt.Errorf("write report: %w", err)
}
return nil
}
func runDetect() {
input, err := readBoundedInput(os.Stdin, maxStdinBytes)
if err != nil {
fatal("read stdin: %v", err)
}
// Detection needs no store.View on GitHub (pinned to 27d5a3981a)
Solutions
- Check the wrapped errno: EPIPE means the consumer closed early; ENOSPC/EROFS mean the redirect target is full or read-only.
- For pipelines, ensure the downstream consumer reads all of stdout or use a temp file instead of a pipe.
- Free disk space or fix permissions on the redirection target.
- Keep the report-on-stderr contract in mind: consume stderr separately, never merge it into stdout.
Example fix
# before: consumer exits early, engine gets EPIPE caveman-engine compress < in | head -c 10 # after: buffer the full payload first caveman-engine compress < in > out.tmp && head -c 10 out.tmp
Defensive patterns
Strategy: validation
Validate before calling
// Ensure stdout is writable and has a consumer before heavy work
if _, err := os.Stdout.Write(nil); err != nil {
return fmt.Errorf("stdout unavailable: %w", err)
} Prevention
- Buffer engine output to a temp file when piping into consumers that may exit early.
- In pipelines, use set -o pipefail so EPIPE surfaces instead of being swallowed.
- Verify the redirect target has space and write permission before starting the run.
When it happens
Trigger: Running caveman-engine with stdout piped into a consumer that exits early (e.g. `caveman-engine compress | head -c 10`), stdout redirected to a full read-only filesystem, or running detached from a closed terminal.
Common situations: Shell pipelines where the next command exits before reading everything; disk full when redirecting to a file; SSH session dropped mid-run; CI capturing stdout into a bounded buffer.
Related errors
- write report: %w
- cave_harness_request_invalid
- cave_eve_terminal_${result.status}
- unknown command ${JSON.stringify(command)}; run caveman-agen
- usage: caveman-agent doctor [--json]
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/73960a46a04b3338.
Report an issue: GitHub.