Auth errors in claude -p are written to stdout instead of stderr
Description
When claude -p / claude --print is used non-interactively, an authentication diagnostic can be emitted on stdout instead of stderr. In the minimal repro below, the process exits with rc=1, but the auth error is written to stdout and stderr is empty.
This is difficult for automation: wrappers commonly treat stdout as assistant output, so the auth diagnostic can be mistaken for a successful model response unless the wrapper also checks the exit code and special-cases known error strings.
Minimal reproduction
Use a throwaway working directory, throwaway config/home paths, and an intentionally invalid API key:
ANTHROPIC_API_KEY=<invalid> \
CLAUDE_CONFIG_DIR=<tmp>/config \
HOME=<tmp>/home \
claude --bare -p 'Say ok' >out 2>err
Observed result
rc=1
stdout: Invalid API key · Fix external API key
stderr: <empty>
Expected result
In non-interactive print mode, authentication failures should be written to stderr, leaving stdout reserved for successful assistant output.
A structured error format would also be useful for automation, but this report is intentionally narrower: auth diagnostics should not be delivered on the same stdout channel as model output.
Environment
- Claude Code version: 2.1.198
- Platform: macOS / Darwin arm64
Related issues checked
- #35540 is related because it requests structured error output and exit-code differentiation for
claude -p, but it is broader and currently closed/locked. - #69864 is related to headless/scheduled
--print401 behavior, but this report is specifically about stdout/stderr stream routing for auth diagnostics.