ducaale/xh · error
Can't use file fields in JSON mode (perhaps you meant…
Error message
Can't use file fields in JSON mode (perhaps you meant --form?)
What it means
File field syntax (`key@file`) is a form/multipart concept. In default JSON mode, `body_from_file` scans the request items for any non-empty `FormFile` and rejects the request, since a JSON object body cannot absorb file uploads — the user almost certainly wanted form mode.
Solutions
- Add `--form`/`-f` (urlencoded) or `--multipart` to the command when using `key@file` fields.
- If the file content should be the entire request body, use a redirect/body syntax (`xh POST :8080 @ photo.png` with content-type) instead of a file field.
- Remove the `@` field if it was included by mistake.
Example fix
// before xh POST :8080 file@photo.png // after xh --form POST :8080 file@photo.png
Defensive patterns
Strategy: validation
Validate before calling
# guard: key@file requires form mode if echo "$args" | grep -qE '[A-Za-z0-9_]+@[^ ]+' && ! echo "$args" | grep -qE -- '--form|--multipart| -f( |$)'; then echo 'file fields need --form or --multipart'; exit 1 fi
Try / catch
match result {
Err(e) if e.to_string().contains("file fields in JSON mode") => {
eprintln!("add --form/-f when using key@file fields");
}
other => other?,
} Prevention
- Pair every key@file usage with --form or --multipart.
- When porting curl -F commands, remember to add form mode.
- Lint CLI builders for @-fields lacking a form flag.
When it happens
Trigger: Running `xh POST :8080 file@photo.png` without `--form`/`-f`/`--multipart` — the `FormFile` item check in `body_from_file` fires the error.
Common situations: Forgetting `-f` when uploading files; migrating curl `-F` commands to xh without adding form mode; tutorials showing `@` syntax without mentioning the required flag.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- JSON values are not supported in Form fields
- JSON values are not supported in multipart fields
- Unsupported option
- Cannot build a multipart request body from stdin
- Request body (from stdin) and request data (key=value)…
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/63276f1952731457.
Report an issue: GitHub.
Appendix: source
Thrown at src/request_items.rs:407
}
RequestItem::HttpHeader(..) => {}
RequestItem::HttpHeaderFromFile(..) => {}
RequestItem::HttpHeaderToUnset(..) => {}
RequestItem::UrlParam(..) => {}
RequestItem::UrlParamFromFile(..) => {}
}
}
Ok(Body::Multipart(form))
}
fn body_from_file(self) -> Result<Body> {
let mut body = None;
if self
.items
.iter()
.any(|item| matches!(item, RequestItem::FormFile {key, ..} if !key.is_empty()))
{
return Err(anyhow!(
"Can't use file fields in JSON mode (perhaps you meant --form?)"
));
}
for item in self.items {
match item {
RequestItem::DataField { .. }
| RequestItem::JsonField(..)
| RequestItem::DataFieldFromFile { .. }
| RequestItem::JsonFieldFromFile(..) => {
return Err(anyhow!(
"Request body (from a file) and request data (key=value) cannot be mixed."
));
}
RequestItem::FormFile {
key,
file_name,
file_type,
file_name_header,View on GitHub (pinned to 2404aceecc)