BoundaryML/baml · error · std::io::Error
compiled output has no unit for `{rel}`
Error message
compiled output has no unit for `{rel}` What it means
While persisting unit artifacts, the cache walks every current user file and needs either a pointer from the reuse plan (for clean files) or an assembled CompilationUnit keyed by the file's root-relative path. If neither exists for `rel`, the compiled output is missing a unit that the project requires, so the store is aborted as corrupt state rather than writing an incomplete manifest.
Source
Thrown at baml_language/crates/baml_cli/src/bytecode_cache.rs:1610
}
let user_files = user_files_with_rel_paths(db, package);
// Only a successful reuse compile returns assembled `units`. A full
// fallback must persist freshly decomposed units for every file rather
// than carrying pointers from the abandoned reuse plan.
let pointer_plan = if reused_units { plan } else { None };
let mut unit_keys = HashMap::with_capacity(user_files.len());
let mut unit_entries_written = 0usize;
for (_, rel) in &user_files {
if let Some(key) = pointer_plan
.filter(|plan| plan.clean_files.contains(rel))
.and_then(|plan| plan.unit_keys.get(rel))
{
unit_keys.insert(rel.clone(), *key);
continue;
}
let Some(unit) = units_by_source.get(rel.as_str()) else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("compiled output has no unit for `{rel}`"),
));
};
if std::path::Path::new(&unit.source_file).is_absolute() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("unit source path is not root-relative: `{rel}`"),
));
}
let (key, wrote) = self.cache.store_unit_shared(unit)?;
unit_entries_written += usize::from(wrote);
unit_keys.insert(rel.clone(), *key.as_bytes());
}
cache_debug(format_args!(
"unit store: wrote {unit_entries_written}, reused {}",
user_files.len().saturating_sub(unit_entries_written)
));View on GitHub (pinned to bd85ce9dee)
Solutions
- Delete the baml bytecode cache directory and rebuild cleanly so no reuse plan or stale units are replayed.
- Make sure no build process mutates the project's .baml files (add/rename/delete) while a compile is in flight.
- Re-run from a clean checkout if a stale generated tree or leftover manifest is suspected.
- If it reproduces deterministically on a clean cache, file a bug with the repro — the unit assembly / reuse-plan pairing is violating its contract.
Example fix
// before: reusing a plan assembled before new files were added store_artifacts_with_manifest(&db, pkg, &compiled, &fresh, Some(&stale_plan)) // after: fall back to a full compile so all units are freshly assembled store_artifacts_with_manifest(&db, pkg, &compiled, &fresh, None)
Defensive patterns
Strategy: validation
Validate before calling
let unit_sources: HashSet<&str> = compiled.units.iter().map(|u| u.source_file.as_str()).collect();
for (_, rel) in &user_files {
assert!(unit_sources.contains(rel.as_str()), "no assembled unit for {rel}");
} Type guard
fn units_cover_all_files(units: &[CompilationUnit], rels: &[String]) -> bool {
let have: HashSet<&str> = units.iter().map(|u| u.source_file.as_str()).collect();
rels.iter().all(|r| have.contains(r.as_str()))
} Try / catch
match result {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData
&& e.to_string().contains("compiled output has no unit") => {
clear_cache_dir();
recompile_without_reuse_plan()
}
other => other?,
} Prevention
- Never mutate the .baml file set while a compile is running.
- Clear the cache after adding/removing/renaming many files at once.
- On InvalidData from store paths, fall back to a full uncached compile rather than retrying reuse.
- Keep cache manifests and unit blobs written atomically to avoid partially-updated state.
When it happens
Trigger: store_artifacts_with_manifest is called with CompiledArtifacts whose units slice (or the ReusePlan's unit_keys, for clean files) does not cover a file returned by user_files_with_rel_paths — e.g. units were assembled from a stale file list, the plan's clean_files contains a rel path absent from both plan.unit_keys and units, or units were built before a file was added to the project.
Common situations: Files added/renamed mid-build while a reuse plan from a previous compile is in play; an out-of-sync or corrupted cache manifest from an interrupted run; a tooling bug that enumerates user files after units were assembled.
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
- duplicate compilation unit for `{}`
- unit source path is not root-relative: `{rel}`
- BAML_CACHE_VERIFY: cached diagnostics for `{}` differ from a
- honest interface fragment for `{}` failed to serialize: {e}
- BAML_CACHE_VERIFY: cached interface fragment for `{}` differ
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/7a16cc2726b9cf99.
Report an issue: GitHub.