{"record":{"id":"80cc65e3a114a293","repo":"BoundaryML/baml","slug":"baml-internal-error-anthropic-file-should-have-been-resolved","errorCode":null,"errorMessage":"BAML internal error (Anthropic): file should have been resolved to base64","messagePattern":"BAML internal error \\(Anthropic\\): file should have been resolved to base64","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs","lineNumber":376,"sourceCode":"    fn to_media_message(\n        &self,\n        mut content: serde_json::Map<String, serde_json::Value>,\n        media: &baml_types::BamlMedia,\n    ) -> Result<serde_json::Map<String, serde_json::Value>> {\n        match media.media_type {\n            baml_types::BamlMediaType::Audio | baml_types::BamlMediaType::Image => {\n                // Standard handling for audio and images\n                match &media.content {\n                    BamlMediaContent::Base64(data) => {\n                        content.insert(\"type\".into(), media.media_type.to_string().into());\n                        let mut source = serde_json::Map::new();\n                        source.insert(\"type\".into(), \"base64\".into());\n                        source.insert(\"media_type\".into(), media.mime_type_as_ok()?.into());\n                        source.insert(\"data\".into(), data.base64.clone().into());\n                        content.insert(\"source\".into(), source.into());\n                    }\n                    BamlMediaContent::File(_) => {\n                        anyhow::bail!(\n                            \"BAML internal error (Anthropic): file should have been resolved to base64\"\n                        )\n                    }\n                    BamlMediaContent::Url(url) => {\n                        content.insert(\"type\".into(), media.media_type.to_string().into());\n                        let mut source = serde_json::Map::new();\n                        source.insert(\"type\".into(), \"url\".into());\n                        source.insert(\"url\".into(), url.url.clone().into());\n                        content.insert(\"source\".into(), source.into());\n                    }\n                }\n            }\n            baml_types::BamlMediaType::Pdf => {\n                // Anthropic supports Pdf inline as Base64 or URL (max 32 MB, 100 pages)\n                match &media.content {\n                    BamlMediaContent::Base64(data) => {\n                        content.insert(\"type\".into(), \"document\".into());\n                        let mut source = serde_json::Map::new();","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-runtime/src/internal/llm_client/primitive/anthropic/anthropic_client.rs#L358-L394","documentation":"When converting BAML media (images/audio) into Anthropic message content, only Base64 or Url content variants are valid at request-build time. A File variant means the media was never pre-processed (resolved/uploaded to base64) as required, so BAML bails with this internal invariant error.","triggerScenarios":"Passing an image/media whose BamlMediaContent is File(_) into to_media_message for the Anthropic client — i.e. media supplied as a raw file path/blob that the media-resolution pipeline failed to convert to base64 before the request.","commonSituations":"Media loading/subprocessing step skipped or failed silently (e.g. node subprocess disabled); passing a very large file that failed conversion; calling the API at a layer that bypasses BAML's media resolution; client/server serialization dropping the resolved content.","solutions":["Pass media as a base64 string or a URL instead of a raw file path/blob","Ensure the BAML runtime can run its media-resolution subprocess (enable file-to-base64 conversion)","Check logs from the media resolution step for silent conversion failures","Upgrade BAML — file resolution handling has been improved in newer versions"],"exampleFix":"// before\nawait b.functions.Describe({ image: b.Image.fromPath('./img.png') }); // file never resolved\n// after\nconst data = fs.readFileSync('./img.png');\nawait b.functions.Describe({ image: b.Image.fromBase64('image/png', data.toString('base64')) });","handlingStrategy":"validation","validationCode":"function assertMediaResolved(media) {\n  if (media && media.file != null && media.base64 == null && media.url == null)\n    throw new Error('Media must be base64 or url before sending to Anthropic');\n}","typeGuard":"const isResolvedMedia = (m) => m != null && (typeof m.base64 === 'string' || typeof m.url === 'string');","tryCatchPattern":"try {\n  return await b.functions.Describe({ image });\n} catch (e) {\n  if (/file should have been resolved to base64/.test(String(e))) {\n    throw new Error('Convert file media to base64 before calling Anthropic-backed functions');\n  }\n  throw e;\n}","preventionTips":["Always pass media via fromBase64/fromUrl, not raw file references","Ensure the runtime media-resolution subprocess can execute","Add a pre-call assertion that media is resolved","Upgrade BAML if file resolution fails silently"],"tags":["anthropic","media","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}