ducaale/xh · error
Request body from stdin and --raw cannot be mixed. Pass…
Error message
Request body from stdin and --raw cannot be mixed. Pass --ignore-stdin to ignore standard input.
What it means
The CLI found both piped stdin content and the --raw flag, which are two competing sources for the raw request body. It refuses to guess and asks the user to pick one, using --ignore-stdin to silence the piped body.
Solutions
- Pass --ignore-stdin so only the --raw body is sent.
- Remove --raw and send the body via stdin instead.
- Feed the raw content through stdin only (e.g. heredoc) and drop the --raw argument.
- Redirect stdin from /dev/null when --raw is used in scripts.
Example fix
// before
cat body.json | xh POST example.org --raw '{"a":1}'
// after
xh POST example.org --raw '{"a":1}' < /dev/null Defensive patterns
Strategy: validation
Validate before calling
if !std::io::stdin().is_terminal() && !ignore_stdin && args.raw.is_some() {
eprintln!("--raw conflicts with piped stdin; add --ignore-stdin or < /dev/null");
std::process::exit(2);
} Try / catch
match run(args) {
Err(e) if e.to_string().contains("--raw cannot be mixed") => {
eprintln!("tip: keep --raw and add --ignore-stdin");
}
other => other,
} Prevention
- Pair every --raw usage with --ignore-stdin in scripts.
- Choose one body source: --raw, stdin, or request items.
- Redirect stdin from /dev/null when the body is provided via flags.
- Review heredoc patterns that leave stdin as a pipe.
When it happens
Trigger: use_stdin is true (stdin piped, --ignore-stdin not set) and args.raw.is_some() in run(), after the request-items check passes.
Common situations: Running `echo x | xh POST url --raw '{...}'` in scripts; CI environments where stdin is a pipe even when unused; combining raw body flags with heredoc/stdin patterns out of habit.
Related errors
- Cannot build a multipart request body from stdin
- Request body (from stdin) and request data (key=value)…
- Message signature components require both…
- JSON values are not supported in Form fields
- JSON values are not supported in multipart fields
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/8cccd850cff6c80f.
Report an issue: GitHub.
Appendix: source
Thrown at src/main.rs:129
let url = url_with_query(args.url, &args.request_items.query()?);
log::debug!("Complete URL: {url}");
let use_stdin = !(args.ignore_stdin || io::stdin().is_terminal() || test_pretend_term());
let body = if use_stdin {
if !args.request_items.is_body_empty() {
if args.multipart {
// Multipart bodies are never "empty", so we can get here without request items
return Err(anyhow!("Cannot build a multipart request body from stdin"));
} else {
return Err(anyhow!(
"Request body (from stdin) and request data (key=value) cannot be mixed. \
Pass --ignore-stdin to ignore standard input."
));
}
}
if args.raw.is_some() {
return Err(anyhow!(
"Request body from stdin and --raw cannot be mixed. \
Pass --ignore-stdin to ignore standard input."
));
}
let mut buffer = Vec::new();
io::stdin().read_to_end(&mut buffer)?;
Body::Raw(buffer)
} else if let Some(raw) = args.raw {
Body::Raw(raw.into_bytes())
} else {
args.request_items.body()?
};
let method = args.method.unwrap_or_else(|| body.pick_method());
log::debug!("HTTP method: {method}");
let mut client = Client::builder()
.http1_title_case_headers()View on GitHub (pinned to 2404aceecc)