BoundaryML/baml · error
Expected a numeric value
Error message
Expected a numeric value
What it means
ValueExpr::resolve_numeric resolves an expression and requires the result to be ResolvedValue::Numeric, returning its textual numeric value. If the expression resolves to a non-numeric variant or fails to resolve, the method throws 'Expected a numeric value' and drops the underlying cause.
Solutions
- Inspect the raw resolved value via resolve() to see what type it actually is.
- Ensure the config value is unquoted numeric (temperature 0.7).
- If from an env var, set it to a plain number (TEMPERATURE=0.7) and verify it is not empty.
- Provide a numeric default in the config so missing env vars still resolve to Numeric.
- Match on resolve() at the call site for a clearer error when scalars are possible.
Example fix
// before (env TEMPERATURE=warm) let t = expr.resolve_numeric(&ctx)?; // Err: Expected a numeric value // after // TEMPERATURE=0.7 (unquoted numeric) or config: temperature 0.7 let t = expr.resolve_numeric(&ctx)?;
Defensive patterns
Strategy: validation
Validate before calling
let resolved = expr.resolve(&ctx)?;
if !matches!(resolved, ResolvedValue::Numeric(_)) {
bail!("value is not numeric: {resolved:?}");
}
let n = expr.resolve_numeric(&ctx)?; Type guard
fn is_numeric(v: &ResolvedValue) -> bool { matches!(v, ResolvedValue::Numeric(..)) } Try / catch
let n = match expr.resolve_numeric(&ctx) {
Ok(n) => n,
Err(_) => "0".to_string(), // safe default
}; Prevention
- Keep numeric config values unquoted and numeric (0.7, not "0.7").
- Set env vars to plain numbers without units or whitespace.
- Provide numeric defaults in config for env-sourced fields.
- Reject non-numeric strings early at config parse time.
When it happens
Trigger: Calling resolve_numeric on an expression that resolves to a string, array, map, or null — e.g. a numeric config field (temperature, max_tokens, retries) interpolated from an unset or non-numeric env var, or quoted in config.
Common situations: Setting TEMPERATURE="warm" in the environment, quoting numbers so they resolve as strings, or leaving the env var unset so resolution falls through to a non-numeric branch.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Could not unify Bool with
- Could not unify Float with
- Expected a boolean
- Expected a map
- Expected a null value
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/b628ec86960bd4ec.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-lib/baml-types/src/value_expr.rs:569
pub fn resolve_array(&self, ctx: &impl GetEnvVar) -> Result<Vec<ResolvedValue>> {
match self.resolve(ctx) {
Ok(ResolvedValue::Array(a, ..)) => Ok(a),
_ => Err(anyhow::anyhow!("Expected an array")),
}
}
pub fn resolve_map(&self, ctx: &impl GetEnvVar) -> Result<IndexMap<String, ResolvedValue>> {
match self.resolve(ctx) {
Ok(ResolvedValue::Map(m, ..)) => Ok(m.into_iter().map(|(k, (_, v))| (k, v)).collect()),
_ => Err(anyhow::anyhow!("Expected a map")),
}
}
pub fn resolve_numeric(&self, ctx: &impl GetEnvVar) -> Result<String> {
match self.resolve(ctx) {
Ok(ResolvedValue::Numeric(n, ..)) => Ok(n),
_ => Err(anyhow::anyhow!("Expected a numeric value")),
}
}
pub fn resolve_null(&self, ctx: &impl GetEnvVar) -> Result<()> {
match self.resolve(ctx) {
Ok(ResolvedValue::Null(..)) => Ok(()),
_ => Err(anyhow::anyhow!("Expected a null value")),
}
}
pub fn resolve_serde<T: serde::de::DeserializeOwned>(&self, ctx: &impl GetEnvVar) -> Result<T> {
let value = self.resolve(ctx)?;
let value: serde_json::Value = value.try_into()?;
match serde_json::from_value(value) {
Ok(v) => Ok(v),
Err(e) => Err(anyhow::anyhow!("Failed to deserialize value: {e}")),
}
}View on GitHub (pinned to bd85ce9dee)