{"record":{"id":"17d49a26e5e2a7c1","repo":"sigoden/aichat","slug":"unexpected-media-type-17d49a","errorCode":null,"errorMessage":"Unexpected media type","messagePattern":"Unexpected media type","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/utils/request.rs","lineNumber":130,"sourceCode":"        \"application/vnd.oasis.opendocument.presentation\" => \"odp\".into(),\n        \"application/rtf\" => \"rtf\".into(),\n        \"text/javascript\" => \"js\".into(),\n        \"text/html\" => \"html\".into(),\n        _ => content_type\n            .rsplit_once('/')\n            .map(|(first, last)| {\n                if [\"image\", \"video\", \"audio\"].contains(&first) {\n                    is_media = true;\n                    MEDIA_URL_EXTENSION.into()\n                } else {\n                    last.to_lowercase()\n                }\n            })\n            .unwrap_or_else(|| DEFAULT_EXTENSION.into()),\n    };\n    let result = if is_media {\n        if !allow_media {\n            bail!(\"Unexpected media type\")\n        }\n        let image_bytes = res.bytes().await?;\n        let image_base64 = base64_encode(&image_bytes);\n        let contents = format!(\"data:{content_type};base64,{image_base64}\");\n        (contents, extension)\n    } else {\n        match loaders.get(&extension) {\n            Some(loader_command) => {\n                let save_path = temp_file(\"-download-\", &format!(\".{extension}\"))\n                    .display()\n                    .to_string();\n                let mut save_file = tokio::fs::File::create(&save_path).await?;\n                let mut size = 0;\n                while let Some(chunk) = res.chunk().await? {\n                    size += chunk.len();\n                    save_file.write_all(&chunk).await?;\n                }\n                let contents = if size == 0 {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/utils/request.rs#L112-L148","documentation":"fetch_with_loaders downloads a URL and, if the response Content-Type is an image/video/audio type (e.g. image/png), requires the caller to have explicitly enabled media handling via `allow_media`. When such a media type is received but `allow_media` is false, it aborts with 'Unexpected media type' instead of embedding the binary as a base64 data URI.","triggerScenarios":"Calling load_documents/load_url on a URL that serves image, video, or audio content (Content-Type like image/*, video/*, audio/*) while media loading is disabled.","commonSituations":"Fetching a link that turns out to be a direct image/binary asset; the URL resolves to an avatar, icon, or media file instead of a text/PDF/document; server redirects a doc URL to a media CDN.","solutions":["Enable the media/allow_media option for this fetch call so the content can be embedded as a base64 data URI","Verify the URL points to a text/document resource rather than a raw media asset","Check the response Content-Type with curl -sI before fetching and convert the media separately if unsupported","Convert or host the media content in a supported format (pdf/html/text) that the loaders can process"],"exampleFix":"// before\nload_documents(&[\"https://example.com/logo.png\"], loaders, false)?;\n// after\nload_documents(&[\"https://example.com/logo.png\"], loaders, true)?; // allow_media = true","handlingStrategy":"validation","validationCode":"async fn content_type_is_media(url: &str) -> anyhow::Result<bool> {\n    let resp = reqwest::get(url).await?;\n    let ct = resp.headers().get(reqwest::header::CONTENT_TYPE)\n        .and_then(|v| v.to_str().ok()).unwrap_or(\"\");\n    Ok([\"image\", \"video\", \"audio\"].iter().any(|t| ct.starts_with(&format!(\"{t}/\"))))\n}\n// if content_type_is_media(url).await? { /* enable allow_media or skip */ }","typeGuard":null,"tryCatchPattern":"match load_url(url, loaders, allow_media).await {\n    Ok((contents, ext)) => { /* use contents */ }\n    Err(e) if e.to_string() == \"Unexpected media type\" => {\n        // re-fetch with allow_media=true or skip this resource\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["HEAD-request the URL and inspect Content-Type before fetching","Enable allow_media when crawling pages known to embed binary assets","Filter or sanitize URL lists to exclude direct media links"],"tags":["http","content-type","media","validation"],"backgroundTag":"unsupported-enum-value","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}