ducaale/xh · error
JSON values are not supported in multipart fields
Error message
JSON values are not supported in multipart fields
What it means
When the request items form a multipart body, to_curl uses curl -F to describe the form; curl cannot express raw JSON values as field values in -F, and xh will not read files to inline them. So JSON-typed fields (=: and =@ JSON-file items) are rejected outright during translation.
Solutions
- Drop --multipart and send JSON fields normally (non-multipart) if no file upload is truly needed
- Replace the JSON field with a plain string field (=) if the server accepts it
- Pass the JSON as an uploaded file part (key@file.json) instead of an inline JSON value
- Send two requests: one multipart upload and one JSON API call, then translate each separately
Example fix
// before
xh --curl -f POST example.org/upload 'meta:={"version":2}' f@data.bin
// after
xh --curl -f POST example.org/upload 'meta@meta.json' f@data.bin Defensive patterns
Strategy: validation
Validate before calling
fn multipart_has_json(items: &[RequestItem]) -> bool {
items.iter().any(|i| matches!(
i,
RequestItem::JsonField(..) | RequestItem::JsonFieldFromFile(..)
))
}
if is_multipart && multipart_has_json(&items) {
eprintln!("remove := / :=@ fields when using --multipart");
std::process::exit(2);
} Type guard
fn is_json_request_item(i: &RequestItem) -> bool {
matches!(i, RequestItem::JsonField(..) | RequestItem::JsonFieldFromFile(..))
} Try / catch
match result {
Err(e) if e.to_string().contains("JSON values are not supported in multipart") => {
eprintln!("convert := fields to = fields or use key@file.json");
}
r => r?,
} Prevention
- Never mix :=/:=@ JSON fields with --multipart
- Use key@file.json to send JSON content as a file part
- When exporting to curl, pre-check request items for JSON-typed fields
When it happens
Trigger: Running `xh --curl` (or --httpie/--print-curl translation) on a command that combines -f/--multipart with JSON fields, e.g. `xh -f POST url 'data:={"a":1}'` or a JsonFieldFromFile item in a multipart request.
Common situations: Users mixing --multipart with := JSON value syntax; converting an existing JSON-body request to multipart for file upload while keeping JSON fields; automated curl export of a mixed request.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- JSON values are not supported in multipart fields
- Unsupported option
- Cannot build a multipart request body from stdin
- expected \n\n
- JSON values are not supported in Form fields
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/81b849e66886eae1.
Report an issue: GitHub.
Appendix: source
Thrown at src/to_curl.rs:384
}
if let Some(raw) = args.raw {
if args.form {
cmd.header("content-type", FORM_CONTENT_TYPE);
} else {
cmd.header("content-type", JSON_CONTENT_TYPE);
cmd.header("accept", JSON_ACCEPT);
}
cmd.opt("-d", "--data");
cmd.arg(raw);
} else if args.request_items.is_multipart() {
// We can't use .body() here because we can't look inside the multipart
// form after construction and we don't want to actually read the files
for item in args.request_items.items {
match item {
RequestItem::JsonField(..) | RequestItem::JsonFieldFromFile(..) => {
return Err(anyhow!("JSON values are not supported in multipart fields"));
}
RequestItem::DataField { key, value, .. } => {
cmd.opt("-F", "--form");
cmd.arg(format!("{key}={value}"));
}
RequestItem::DataFieldFromFile { key, value, .. } => {
cmd.opt("-F", "--form");
cmd.arg(format!("{key}=<{value}"));
}
RequestItem::FormFile {
key,
file_name,
file_type,
file_name_header,
} => {
cmd.opt("-F", "--form");
let mut val = format!("{key}=@{file_name}");
if let Some(file_type) = file_type {View on GitHub (pinned to 2404aceecc)