BoundaryML/baml · error

Failed to resolve

Error message

Failed to resolve {}

What it means

In the WASM (browser/JS) environment, GCP credentials that still contain an unresolved environment-variable placeholder (a string starting with '$') cannot be expanded, because the WASM runtime has no access to host environment variables. The auth strategy constructor bails with this message naming the unresolved string.

Solutions

  1. Inject the actual credential value (file path or JSON) into the runtime config instead of a $VAR reference when running in WASM
  2. Pre-resolve environment variables in your JS wrapper before passing config to the WASM runtime
  3. For browser deployments, use a proxy/backend to hold GCP credentials rather than embedding them client-side
  4. Verify the env var is set in the build/deploy pipeline so placeholder substitution actually occurs

Example fix

// before (WASM config with unresolved placeholder)
auth { strategy "StringContainingJson" "$GOOGLE_APPLICATION_CREDENTIALS_JSON" }
// after: resolve before passing in
const creds = process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON; // or injected at build time
auth { strategy "StringContainingJson" creds }
Defensive patterns

Strategy: validation

Validate before calling

function assertNoUnresolvedEnvVars(cfg) {
  for (const v of Object.values(cfg?.options?.credentials ?? {})) {
    if (typeof v === 'string' && v.startsWith('$')) {
      throw new Error(`Unresolved env placeholder '${v}' — resolve it before passing to the WASM runtime`);
    }
  }
}

Type guard

const isResolvedCredential = (v) => typeof v === 'string' && v.length > 0 && !v.startsWith('$');

Try / catch

try {
  const client = new BamlClient(config);
} catch (err) {
  if (String(err).startsWith('Failed to resolve $')) {
    throw new Error(`Env var ${String(err).split(' ')[3]} is unavailable in WASM; inject its value instead`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Running BAML compiled to WASM with a GCP auth strategy whose credentials path or JSON string is something like '$GOOGLE_APPLICATION_CREDENTIALS' and that env var was never substituted before reaching the runtime.

Common situations: Using the same BAML config on server (env vars resolved) and in the browser/WASM (env vars unavailable); forgetting to inline or inject the credential value in a web deployment.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/5cc8dd7ec9acddba. Report an issue: GitHub.

Appendix: source

Thrown at engine/baml-runtime/src/internal/llm_client/primitive/vertex/wasm_auth.rs:34

impl Token {
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl VertexAuth {
    pub async fn get_or_create(auth_strategy: &ResolvedGcpAuthStrategy) -> Result<Arc<VertexAuth>> {
        // For WASM, just create new instances without caching
        let auth = Arc::new(Self::new(auth_strategy).await?);
        Ok(auth)
    }

    pub async fn new(auth_strategy: &ResolvedGcpAuthStrategy) -> Result<Self> {
        Ok(match auth_strategy {
            ResolvedGcpAuthStrategy::MaybeFilePath(str)
            | ResolvedGcpAuthStrategy::StringContainingJson(str) => {
                if str.starts_with("$") {
                    anyhow::bail!("Failed to resolve {}", str);
                }

                let debug_str = {
                    let s = serde_json::to_string(&serde_json::Value::String(str.clone()))
                        .expect("Serialization of string should always succeed");
                    if s.len() > 8 {
                        format!("{}...{}", &s[..4], &s[s.len() - 4..])
                    } else {
                        s
                    }
                };

                log::debug!("Attempting to auth using JsonString strategy");
                Self(Some(serde_json::from_str(str).context(format!("Failed to parse 'credentials' as GCP service account creds (are you using JSON format creds?); credentials={debug_str}"))?))
            }
            ResolvedGcpAuthStrategy::JsonObject(json) => {
                // NB: this should never happen in WASM, there's no way to pass a JSON object in
                log::debug!("Attempting to auth using JsonObject strategy");

View on GitHub (pinned to bd85ce9dee)