BoundaryML/baml · error
generic media cannot inhabit a concrete prompt part
Error message
generic media cannot inhabit a concrete prompt part
What it means
This panic fires when the BAML VM tries to render a media value into a concrete prompt part but the media's kind is `Generic`. Generic media is a placeholder/type-level carrier that has no concrete prompt class (Image/Audio/Video/Pdf), so the VM treats its presence in a prompt as an unrecoverable compiler/VM invariant violation rather than a user error.
Solutions
- Ensure the media value is a concrete kind (Image/Audio/Video/Pdf) before inserting it into a prompt part; construct it via the corresponding media constructor.
- Check the static type of the field/expression feeding the prompt; if it is generic media, narrow or convert it explicitly.
- Report this to the BAML maintainers if a well-typed program hits it — it indicates a VM invariant leak.
Example fix
// before (generic media flowing into prompt) prompt: media_value // after prompt: media_value as baml.media.Image // ensure concrete media kind is used
Defensive patterns
Strategy: type-guard
Validate before calling
// before inserting media into a prompt
if media.kind == "Generic" { throw new Error("media must be a concrete kind (image/audio/video/pdf) before use in a prompt"); } Type guard
function isConcreteMedia(m) { return m && m.kind !== undefined && ["Image","Audio","Video","Pdf"].includes(m.kind); } Prevention
- Only pass media constructed via concrete media constructors into prompt parts.
- Narrow generic media types before prompt use.
- Keep type annotations strict so unspecialized media cannot reach prompts.
When it happens
Trigger: Calling prompt construction (prompt_content_values, reached via messages) with a value whose MediaKind is Generic — e.g. media produced by a generic-typed field or API path that did not specialize to image/audio/video/pdf before being placed into a prompt part.
Common situations: Assigning a generically-typed media (e.g. from a `media` union or dynamic input) directly into a prompt; a type-checking gap that let unspecialized media reach prompt rendering; wiring a media value read from external data without refining its kind.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- : expected float at index , got
- : expected int at index
- Future short-circuited above
- PlainDate.to_plain_datetime: expected PlainDate instance
- PlainDateTime.to_plain_date: expected PlainDateTime instance
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/4460e68cfe109679.
Report an issue: GitHub.
Appendix: source
Thrown at baml_language/crates/bex_vm/src/package_baml/prompt.rs:375
fn prompt_metadata_value(vm: &mut BexVm, metadata: serde_json::Value) -> Value {
let metadata = match metadata {
serde_json::Value::Object(_) => metadata,
_ => serde_json::Value::Object(serde_json::Map::new()),
};
super::json::serde_to_value(vm, &metadata)
}
fn prompt_content_values(vm: &mut BexVm, content: &PromptAstSimple) -> Vec<Value> {
match content {
PromptAstSimple::String(text) => vec![Value::object(vm.alloc_string(text.clone()))],
PromptAstSimple::Media(media) => {
let class_name = match media.kind {
baml_type::MediaKind::Image => "baml.media.Image",
baml_type::MediaKind::Audio => "baml.media.Audio",
baml_type::MediaKind::Video => "baml.media.Video",
baml_type::MediaKind::Pdf => "baml.media.Pdf",
baml_type::MediaKind::Generic => {
panic!("generic media cannot inhabit a concrete prompt part")
}
};
let class = vm.resolve_class(class_name);
let data = Value::object(vm.alloc_rust_data(media.clone()));
vec![Value::object(vm.alloc_instance(class, vec![data]))]
}
PromptAstSimple::Multiple(parts) => parts
.iter()
.flat_map(|part| prompt_content_values(vm, part.as_ref()))
.collect(),
}
}
impl BamlNamespaceInternal for PackageAiImpl {
fn assemble_prompt(vm: &mut BexVm, parts: &[Value], values: &[Value]) -> NativeCallResult {
let mut pending = Vec::new();
for value in values.iter().copied() {
if prompt_role(vm, value).is_none()View on GitHub (pinned to bd85ce9dee)