BoundaryML/baml · error
UnscheduledFuture cannot be serialized
Error message
UnscheduledFuture cannot be serialized
What it means
`UnscheduledFuture` is a runtime spawn-request slot with the same lifecycle shape as `Future` and is never baked into a compiled `Program`. Its `BorshSerialize` impl is an intentional always-fail stub: if an `UnscheduledFuture` reaches the serializer (the `baml_exec::PackEnvelope` that serializes bytecode + constant heap), the program is malformed and the library fails fast with `InvalidData`.
Source
Thrown at baml_language/crates/bex_vm_types/src/types/future.rs:144
}
impl BorshDeserialize for Future {
fn deserialize_reader<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Future cannot be deserialized",
))
}
}
// `UnscheduledFuture` is a runtime spawn-request slot — same lifecycle
// shape as `Future`, never appears in a compiled `Program`. The pack
// envelope (`baml_exec::PackEnvelope`) serializes the bytecode + the
// constant heap; if an `UnscheduledFuture` ever reaches the serializer
// that's a malformed program and we want to fail fast.
impl BorshSerialize for UnscheduledFuture {
fn serialize<W: std::io::Write>(&self, _writer: &mut W) -> std::io::Result<()> {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"UnscheduledFuture cannot be serialized",
))
}
}
impl BorshDeserialize for UnscheduledFuture {
fn deserialize_reader<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"UnscheduledFuture cannot be deserialized",
))
}
}
// `Future::read` calls `MaybeUninit::<Value>::assume_init_read`, which is
// sound only because `Value: Copy`. If `Value` ever gains a non-trivial
// `Drop` (e.g. by holding an `Arc<…>` or `Box<…>`), `assume_init_read`View on GitHub (pinned to bd85ce9dee)
Solutions
- Fix the pack builder so spawn-request values never enter the serialized bytecode or constant heap.
- Audit the value that reached serialization (`Object::UnscheduledFuture` variant) and route it through a runtime-only path instead.
- Rebuild the artifact with a correct compiler; never persist unscheduled spawn slots.
Example fix
// before: packing a live heap that still holds an UnscheduledFuture let pack = PackEnvelope::new(program, heap_with_spawn_slot); // io::Error: UnscheduledFuture cannot be serialized // after: strip runtime-only values before packing let heap = heap_without_runtime_values(&live_heap); // keeps futures/spawn slots out let pack = PackEnvelope::new(program, heap);
Defensive patterns
Strategy: validation
Validate before calling
// before building a pack
assert!(
!pool.iter().any(|o| matches!(o, Object::UnscheduledFuture(_))),
"UnscheduledFuture reached the pack serializer: malformed program"
); Type guard
fn is_unscheduled_future(v: &Value) -> bool {
matches!(v, Value::Object(o) if matches!(&*o.borrow(), Object::UnscheduledFuture(_)))
} Prevention
- Strip runtime-only spawn slots from the heap before pack export.
- Route spawn requests through the engine registry instead of the serialized object pool.
- Fail at pack-build time with a clear invariant check rather than at Borsh's serializer.
- Fuzz/round-trip the pack format with the invariant that runtime variants never appear.
When it happens
Trigger: Calling `borsh::to_writer`/`serialize` on an `UnscheduledFuture`, or serializing a container (`Object`, `Value`, object pool) that holds one while building a pack.
Common situations: A VM bug that leaks a pending spawn request into the constant heap or object pool before pack serialization; misuse of the public serialization API on live VM values; fuzz/round-trip testing of the pack format.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Future cannot be deserialized
- invalid package interface: {message}
- variant `{}` requires an explicit discriminant to stabilize
- UnscheduledFuture cannot be deserialized
- RustData cannot be serialized
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/5e75e518e3df3047.
Report an issue: GitHub.