BoundaryML/baml · error · anyhow::Error
readFileRef did not return a promise
Error message
readFileRef did not return a promise
What it means
The readFileRef callback injected from JS (get_baml_src_cb) was expected to return a Promise for the given adjusted path, but calling it returned null/undefined or threw synchronously. The Rust WASM runtime bails so it cannot read the BAML source file asynchronously.
Solutions
- Ensure the readFileRef option is an async function returning a Promise<ArrayBuffer|Uint8Array>
- Confirm readFileRef is registered/defined before BAML runtime initialization
- Validate the path passed to readFileRef resolves in the host environment
- Check that the callback doesn't throw synchronously before returning the promise
Example fix
// before
b.init({ readFileRef: (path) => fs.readFileSync(path) })
// after
b.init({ readFileRef: async (path) => fs.promises.readFile(path) }) Defensive patterns
Strategy: validation
Validate before calling
// validate readFileRef before initializing BAML
if (typeof opts.readFileRef !== 'function') throw new Error('readFileRef must be a function');
const probe = opts.readFileRef('probe.baml');
if (!(probe instanceof Promise)) throw new Error('readFileRef must return a Promise (make it async)'); Type guard
const isReadFileRef = (f) => typeof f === 'function' && f('x') instanceof Promise; Try / catch
try {
await b.init(opts);
} catch (e) {
if (String(e).includes('readFileRef did not return a promise')) {
console.error('readFileRef must be async and return a Promise');
}
throw e;
} Prevention
- Always declare readFileRef as an async function returning a Promise<Uint8Array|ArrayBuffer>
- Register readFileRef before any BAML runtime call
- Smoke-test readFileRef with one real path at startup
When it happens
Trigger: invoke get_baml_src_cb.call1(...) in the wasm runtime when the JS host's readFileRef is not a function returning a Promise, is undefined, or throws before returning (e.g. invalid path rejected synchronously).
Common situations: Using BAML in a JS/TS environment (Next.js, Vite, browser) where the readFileRef option is misconfigured — passed a sync function, an async wrapper mismatch, or omitted so the callback misbehaves.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- readFileRef failure
- readFileRef rejected
- Failed to recv cred response across WASM bridge
- Failed to send cred request across WASM bridge
- JavaScript error
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/a56c02a3d447e814.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-schema-wasm/src/runtime_wasm/mod.rs:2375
if is_windows && (path.starts_with("../") || path.starts_with("./")) {
let result = format!("baml_src/{path}");
web_sys::console::log_1(&wasm_bindgen::JsValue::from_str(&format!(
"WASM Windows path fix applied: '{path}' → '{result}'"
)));
result
} else {
web_sys::console::log_1(&wasm_bindgen::JsValue::from_str(&format!(
"WASM path unchanged: '{}' (windows={}, relative={})",
path,
is_windows,
path.starts_with("../") || path.starts_with("./")
)));
path.clone()
};
let null = JsValue::NULL;
let Ok(read) = get_baml_src_cb.call1(&null, &JsValue::from(adjusted_path)) else {
anyhow::bail!("readFileRef did not return a promise");
};
let read = JsFuture::from(Promise::unchecked_from_js(read)).await;
let read = match read {
Ok(read) => read,
Err(err) => {
if let Some(e) = err.dyn_ref::<js_sys::Error>() {
if let Some(e_str) = e.message().as_string() {
anyhow::bail!("readFileRef failure: {}", e_str);
}
}
anyhow::bail!("readFileRef rejected: {:?}", err);
}
};
// TODO: how does JsValue -> Uint8Array work without try_from?View on GitHub (pinned to bd85ce9dee)