ducaale/xh · error

JSON values are not supported in Form fields

Error message

JSON values are not supported in Form fields

What it means

When building an `application/x-www-form-urlencoded` body, every request item must be a plain string key/value. `RequestItem::JsonField` (the `key:=value` syntax) carries typed JSON values that cannot be represented as form text fields, so `body_as_form` aborts with this error.

Solutions

  1. Remove the `:=` (raw JSON) fields or convert them to `=` string fields when using form mode.
  2. Drop `--form`/`-f` if you actually want a JSON body, and use `=`/`:=` fields freely.
  3. Use `--multipart` with file fields only, keeping value fields as plain `key=value`.

Example fix

// before
xh --form POST :8080 name=John count:=2
// after
xh POST :8080 name=John count:=2
Defensive patterns

Strategy: validation

Validate before calling

# guard: form mode must not contain := items
if [[ "$*" == *--form* || "$*" == *" -f "* ]] && echo "$*" | grep -q ':='; then
  echo 'JSON (:=) fields are invalid with --form'; exit 1
fi

Try / catch

match result {
    Err(e) if e.to_string().contains("not supported in Form fields") => {
        eprintln!("use = fields with --form, or drop --form for := fields");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Mixing `=` (data) and `:=` (raw JSON) operators without `--json` mode being in effect, e.g. `xh --form POST :8080 name=John count:=2` — the `:=` item triggers the error inside `body_as_form`.

Common situations: Copying JSON-mode examples and adding `--form`/`-f` for file uploads; scripts that append `:=` fields to form submissions; forgetting that `-f` forces form serialization for all fields.

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/7a6eec7a2996ece7. Report an issue: GitHub.

Appendix: source

Thrown at src/request_items.rs:343

                | RequestItem::HttpHeaderFromFile(..)
                | RequestItem::HttpHeaderToUnset(..)
                | RequestItem::UrlParam(..)
                | RequestItem::UrlParamFromFile(..) => continue,
            };
            let json_path = nested_json::parse_path(&raw_key)?;
            body = nested_json::insert(body, &json_path, value)
                .map_err(|e| e.with_json_path(raw_key))?
                .into();
        }
        Ok(Body::Json(body.unwrap_or(Value::Null)))
    }

    fn body_as_form(self) -> Result<Body> {
        let mut text_fields = Vec::<(String, String)>::new();
        for item in self.items {
            match item {
                RequestItem::JsonField(..) | RequestItem::JsonFieldFromFile(..) => {
                    return Err(anyhow!("JSON values are not supported in Form fields"));
                }
                RequestItem::DataField { key, value, .. } => text_fields.push((key, value)),
                RequestItem::DataFieldFromFile { key, value, .. } => {
                    let path = expand_tilde(value);
                    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> {

View on GitHub (pinned to 2404aceecc)