BoundaryML/baml · error · napi::Error
{e:?}
Error message
{e:?} What it means
Span::new fails when the args JSON passed to start a call cannot be deserialized into a BamlValue, or when env_vars cannot be deserialized into HashMap<String,String>; the raw serde error is formatted with {e:?}. It indicates malformed input to the span/tracing API.
Solutions
- Ensure args is a JSON object of serializable values before calling Span.new
- Ensure env_vars is a flat object of string-to-string (e.g. { ...process.env })
- Read the serde Debug error {e:?} to see the exact field/type that failed
- Wrap args/env_vars in JSON.stringify/parse to normalize them
Example fix
// before
const span = ctx.startSpan('MyFunc', args, ctxManager, process.env);
// after
const envVars = Object.fromEntries(Object.entries(process.env).map(([k, v]) => [k, String(v ?? '')]));
const span = ctx.startSpan('MyFunc', JSON.parse(JSON.stringify(args)), ctxManager, envVars); Defensive patterns
Strategy: validation
Validate before calling
function assertSpanInputs(args, envVars) {
if (typeof args !== 'object' || args === null || Array.isArray(args)) throw new Error('span args must be a JSON object');
const badEnv = Object.entries(envVars ?? {}).filter(([, v]) => typeof v !== 'string');
if (badEnv.length) throw new Error('env_vars values must all be strings: ' + badEnv.map(([k]) => k).join(','));
} Type guard
const isValidSpanArgs = (args: unknown): args is Record<string, unknown> => typeof args === 'object' && args !== null && !Array.isArray(args);
Try / catch
let span;
try {
span = ctx.startSpan(fnName, args, ctxManager, envVars);
} catch (e) {
console.error('startSpan failed:', String(e));
span = null; // proceed without tracing rather than crashing
} Prevention
- Always pass env vars as a flat string-to-string object
- Serialize args through JSON.stringify/parse to strip non-JSON values
- Log args shape in dev mode before starting spans
- Keep span payloads limited to plain serializable data
When it happens
Trigger: Calling Span.new (via the runtime context manager) with args that aren't valid JSON values BAML understands, or env_vars containing non-string values (numbers, booleans, nested objects).
Common situations: Passing JS objects with unsupported field types, passing process.env values that were coerced incorrectly, or sending args that aren't a JSON object at all.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/50bd01a23b49ba55.
Report an issue: GitHub.
Appendix: source
Thrown at engine/language_client_typescript/src/types/span.rs:27
crate::lang_wrapper!(BamlSpan,
Option<baml_runtime::tracing::TracingCall>,
no_from,
rt: std::sync::Arc<CoreBamlRuntime>
);
#[napi]
impl BamlSpan {
#[napi(ts_return_type = "BamlSpan")]
pub fn new(
runtime: &BamlRuntime,
function_name: String,
args: serde_json::Value,
ctx: &RuntimeContextManager,
env_vars: serde_json::Value,
) -> napi::Result<Self> {
let args: BamlValue = serde_json::from_value(args)
.map_err(|e| napi::Error::new(napi::Status::GenericFailure, format!("{e:?}")))?;
let Some(args_map) = args.as_map() else {
return Err(invalid_argument_error("Invalid span args"));
};
let env_vars: HashMap<String, String> = serde_json::from_value(env_vars)
.map_err(|e| napi::Error::new(napi::Status::GenericFailure, format!("{e:?}")))?;
let call = runtime
.inner
.start_call(&function_name, args_map, &ctx.inner, &env_vars);
log::trace!("Starting call: {call:#?} for {function_name:?}\n");
Ok(Self {
inner: call.into(),
rt: runtime.inner.clone(),
})
}
// mthod to finishView on GitHub (pinned to bd85ce9dee)