ducaale/xh · error
Request body (from stdin) and request data (key=value)…
Error message
Request body (from stdin) and request data (key=value) cannot be mixed. Pass --ignore-stdin to ignore standard input.
What it means
The CLI detected piped stdin content and also request data items (key=value), which would require mixing a raw stdin body with form fields — impossible in a single request. It errors and suggests --ignore-stdin.
Solutions
- Pass --ignore-stdin to discard piped stdin and send only the key=value request items.
- Remove the key=value items and send the stdin body alone (e.g. with a Content-Type header).
- Move the stdin content into a request item such as field@file instead of piping.
- Run from an interactive terminal or explicitly redirect stdin from /dev/null.
Example fix
// before
echo '{"a":1}' | xh POST example.org key=value
// after
echo '{"a":1}' | xh --ignore-stdin POST example.org key=value Defensive patterns
Strategy: validation
Validate before calling
if !std::io::stdin().is_terminal() && !ignore_stdin && !request_items.is_body_empty() {
eprintln!("piping a body and key=value items cannot be mixed; add --ignore-stdin");
std::process::exit(2);
} Try / catch
match run(args) {
Err(e) if e.to_string().contains("cannot be mixed") => {
eprintln!("tip: add --ignore-stdin or drop the key=value items");
}
other => other,
} Prevention
- Default to --ignore-stdin in shell scripts and CI.
- Send either a stdin body OR request items, never both.
- Convert stdin payloads into a file and pass it with a request item when fields are needed.
- Use explicit input redirection to document data flow in scripts.
When it happens
Trigger: use_stdin is true (stdin piped, --ignore-stdin not set), args.request_items.is_body_empty() is false, and args.multipart is false in run().
Common situations: Piping JSON with `echo data | xh POST url key=value`; shell scripts where stdin happens to be a pipe in CI; forgetting that a non-terminal stdin counts as a body.
Related errors
- Cannot build a multipart request body from stdin
- Request body from stdin and --raw cannot be mixed. Pass…
- Request body (from a file) and request data (key=value)…
- Message signature components require both…
- JSON values are not supported in Form fields
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/cf4fa152751938d3.
Report an issue: GitHub.
Appendix: source
Thrown at src/main.rs:122
if args.curl {
to_curl::print_curl_translation(args)?;
return Ok(ExitCode::SUCCESS);
}
let (mut headers, headers_to_unset) = args.request_items.headers()?;
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()?View on GitHub (pinned to 2404aceecc)