{"record":{"id":"5cc8dd7ec9acddba","repo":"BoundaryML/baml","slug":"failed-to-resolve","errorCode":null,"errorMessage":"Failed to resolve {}","messagePattern":"Failed to resolve (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-runtime/src/internal/llm_client/primitive/vertex/wasm_auth.rs","lineNumber":34,"sourceCode":"impl Token {\n    pub fn as_str(&self) -> &str {\n        &self.0\n    }\n}\n\nimpl VertexAuth {\n    pub async fn get_or_create(auth_strategy: &ResolvedGcpAuthStrategy) -> Result<Arc<VertexAuth>> {\n        // For WASM, just create new instances without caching\n        let auth = Arc::new(Self::new(auth_strategy).await?);\n        Ok(auth)\n    }\n\n    pub async fn new(auth_strategy: &ResolvedGcpAuthStrategy) -> Result<Self> {\n        Ok(match auth_strategy {\n            ResolvedGcpAuthStrategy::MaybeFilePath(str)\n            | ResolvedGcpAuthStrategy::StringContainingJson(str) => {\n                if str.starts_with(\"$\") {\n                    anyhow::bail!(\"Failed to resolve {}\", str);\n                }\n\n                let debug_str = {\n                    let s = serde_json::to_string(&serde_json::Value::String(str.clone()))\n                        .expect(\"Serialization of string should always succeed\");\n                    if s.len() > 8 {\n                        format!(\"{}...{}\", &s[..4], &s[s.len() - 4..])\n                    } else {\n                        s\n                    }\n                };\n\n                log::debug!(\"Attempting to auth using JsonString strategy\");\n                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}\"))?))\n            }\n            ResolvedGcpAuthStrategy::JsonObject(json) => {\n                // NB: this should never happen in WASM, there's no way to pass a JSON object in\n                log::debug!(\"Attempting to auth using JsonObject strategy\");","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-runtime/src/internal/llm_client/primitive/vertex/wasm_auth.rs#L16-L52","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inject the actual credential value (file path or JSON) into the runtime config instead of a $VAR reference when running in WASM","Pre-resolve environment variables in your JS wrapper before passing config to the WASM runtime","For browser deployments, use a proxy/backend to hold GCP credentials rather than embedding them client-side","Verify the env var is set in the build/deploy pipeline so placeholder substitution actually occurs"],"exampleFix":"// before (WASM config with unresolved placeholder)\nauth { strategy \"StringContainingJson\" \"$GOOGLE_APPLICATION_CREDENTIALS_JSON\" }\n// after: resolve before passing in\nconst creds = process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON; // or injected at build time\nauth { strategy \"StringContainingJson\" creds }","handlingStrategy":"validation","validationCode":"function assertNoUnresolvedEnvVars(cfg) {\n  for (const v of Object.values(cfg?.options?.credentials ?? {})) {\n    if (typeof v === 'string' && v.startsWith('$')) {\n      throw new Error(`Unresolved env placeholder '${v}' — resolve it before passing to the WASM runtime`);\n    }\n  }\n}","typeGuard":"const isResolvedCredential = (v) => typeof v === 'string' && v.length > 0 && !v.startsWith('$');","tryCatchPattern":"try {\n  const client = new BamlClient(config);\n} catch (err) {\n  if (String(err).startsWith('Failed to resolve $')) {\n    throw new Error(`Env var ${String(err).split(' ')[3]} is unavailable in WASM; inject its value instead`);\n  }\n  throw err;\n}","preventionTips":["Substitute all $VAR placeholders in JS before handing config to the WASM runtime","Do not reuse server-side env-var-based configs verbatim in browser builds","Centralize credential injection in one config-builder function used by both server and WASM entry points"],"tags":["wasm","gcp","credentials","environment-variable"],"backgroundTag":"missing-env-var","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}