{"record":{"id":"63276f1952731457","repo":"ducaale/xh","slug":"can-t-use-file-fields-in-json-mode-perhaps-you-meant-form","errorCode":null,"errorMessage":"Can't use file fields in JSON mode (perhaps you meant --form?)","messagePattern":"Can't use file fields in JSON mode \\(perhaps you meant --form\\?\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/request_items.rs","lineNumber":407,"sourceCode":"                }\n                RequestItem::HttpHeader(..) => {}\n                RequestItem::HttpHeaderFromFile(..) => {}\n                RequestItem::HttpHeaderToUnset(..) => {}\n                RequestItem::UrlParam(..) => {}\n                RequestItem::UrlParamFromFile(..) => {}\n            }\n        }\n        Ok(Body::Multipart(form))\n    }\n\n    fn body_from_file(self) -> Result<Body> {\n        let mut body = None;\n        if self\n            .items\n            .iter()\n            .any(|item| matches!(item, RequestItem::FormFile {key, ..} if !key.is_empty()))\n        {\n            return Err(anyhow!(\n                \"Can't use file fields in JSON mode (perhaps you meant --form?)\"\n            ));\n        }\n        for item in self.items {\n            match item {\n                RequestItem::DataField { .. }\n                | RequestItem::JsonField(..)\n                | RequestItem::DataFieldFromFile { .. }\n                | RequestItem::JsonFieldFromFile(..) => {\n                    return Err(anyhow!(\n                        \"Request body (from a file) and request data (key=value) cannot be mixed.\"\n                    ));\n                }\n                RequestItem::FormFile {\n                    key,\n                    file_name,\n                    file_type,\n                    file_name_header,","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/ducaale/xh/blob/2404aceecc08b0b2d100fedc96f57745cd5904dc/src/request_items.rs#L389-L425","documentation":"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.","triggerScenarios":"Running `xh POST :8080 file@photo.png` without `--form`/`-f`/`--multipart` — the `FormFile` item check in `body_from_file` fires the error.","commonSituations":"Forgetting `-f` when uploading files; migrating curl `-F` commands to xh without adding form mode; tutorials showing `@` syntax without mentioning the required flag.","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."],"exampleFix":"// before\nxh POST :8080 file@photo.png\n// after\nxh --form POST :8080 file@photo.png","handlingStrategy":"validation","validationCode":"# guard: key@file requires form mode\nif echo \"$args\" | grep -qE '[A-Za-z0-9_]+@[^ ]+' && ! echo \"$args\" | grep -qE -- '--form|--multipart| -f( |$)'; then\n  echo 'file fields need --form or --multipart'; exit 1\nfi","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"file fields in JSON mode\") => {\n        eprintln!(\"add --form/-f when using key@file fields\");\n    }\n    other => other?,\n}","preventionTips":["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."],"tags":["http","json","form","file-upload","cli"],"backgroundTag":"incompatible-source-type","analyzedSha":"2404aceecc08b0b2d100fedc96f57745cd5904dc","analyzedAt":"2026-09-13T19:13:33.814Z","contentChangedAt":"2026-09-13T19:13:33.814Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}