ducaale/xh · error

JSON values are not supported in multipart fields

Error message

JSON values are not supported in multipart fields

What it means

Multipart bodies consist of named parts with text or binary content; raw JSON typed values from `key:=value` items have no multipart representation. `body_as_multipart` therefore rejects any `RequestItem::JsonField`/`JsonFieldFromFile` item with this error.

Solutions

  1. Convert `:=` items to plain `key=value` text fields when in multipart mode.
  2. Remove `--multipart`/`--form` if you need typed JSON values in the body.
  3. Send the JSON part separately, e.g. as a JSON string field: `json='{"count":2}'`.

Example fix

// before
xh --multipart POST :8080 file@photo.png count:=2
// after
xh --multipart POST :8080 file@photo.png count=2
Defensive patterns

Strategy: validation

Validate before calling

# guard: multipart must not contain := items
if echo "$args" | grep -q -- '--multipart' && echo "$args" | grep -q ':='; then
  echo 'JSON (:=) fields are invalid in multipart'; exit 1
fi

Try / catch

match result {
    Err(e) if e.to_string().contains("not supported in multipart") => {
        eprintln!("convert := items to plain text fields for multipart");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running `xh --multipart POST :8080 name=John count:=2` (or `--form` with multipart resolved), where a `:=` or `@file:=` item is present among the request items.

Common situations: Uploading files with `--multipart` while keeping JSON fields from an earlier JSON-mode command line; generated command lines that append `:=` items regardless of body mode.

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


AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13). Data as JSON: /api/errors/29dc1a07b0af38cd. Report an issue: GitHub.

Appendix: source

Thrown at src/request_items.rs:366

                    text_fields.push((key, fs::read_to_string(path)?));
                }
                RequestItem::FormFile { .. } => unreachable!(),
                RequestItem::HttpHeader(..) => {}
                RequestItem::HttpHeaderFromFile(..) => {}
                RequestItem::HttpHeaderToUnset(..) => {}
                RequestItem::UrlParam(..) => {}
                RequestItem::UrlParamFromFile(..) => {}
            }
        }
        Ok(Body::Form(text_fields))
    }

    fn body_as_multipart(self) -> Result<Body> {
        let mut form = multipart::Form::new();
        for item in self.items {
            match item {
                RequestItem::JsonField(..) | RequestItem::JsonFieldFromFile(..) => {
                    return Err(anyhow!("JSON values are not supported in multipart fields"));
                }
                RequestItem::DataField { key, value, .. } => {
                    form = form.text(key, value);
                }
                RequestItem::DataFieldFromFile { key, value, .. } => {
                    let path = expand_tilde(value);
                    form = form.text(key, fs::read_to_string(path)?);
                }
                RequestItem::FormFile {
                    key,
                    file_name,
                    file_type,
                    file_name_header,
                } => {
                    let mut part = file_to_part(expand_tilde(file_name))?;
                    if let Some(file_type) = file_type {
                        part = part.mime_str(&file_type)?;
                    }

View on GitHub (pinned to 2404aceecc)