BoundaryML/baml · error
{e:?}
Error message
{e:?} What it means
When exchanging the signed JWT for an OAuth2 access token with Google's token endpoint, any failure from `encode_jwt` (JWT signing/encoding) is re-thrown with its Debug formatting. This surfaces JWT construction failures — most commonly key parsing or serialization errors — without a friendly message.
Source
Thrown at engine/baml-runtime/src/internal/llm_client/primitive/vertex/wasm_auth.rs:149
}
}
}
#[derive(Debug, Deserialize)]
pub struct ServiceAccount {
pub token_uri: String,
pub project_id: String,
pub client_email: String,
pub private_key: String,
}
impl ServiceAccount {
async fn get_oauth2_token(&self) -> Result<Token> {
let claims = Claims::from_service_account(self);
let jwt = encode_jwt(&serde_json::to_value(claims)?, &self.private_key)
.await
.map_err(|e| anyhow::anyhow!(format!("{e:?}")))?;
// Make the token request
let client = reqwest::Client::new();
let params = [
("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"),
("assertion", &jwt),
];
let res = client
.post(&self.token_uri)
.form(¶ms)
.send()
.await?
.text()
.await?;
parse_token_response(&res).context(format!("OAuth2 access token request failed: {res}"))
}
}View on GitHub (pinned to bd85ce9dee)
Solutions
- Inspect the inner error text (`e:?` in the message) to identify whether it is key parsing or serialization; read the full Debug string in logs.
- Re-download the service account JSON key from GCP Console and load it verbatim (fix escaped `\n` in private_key).
- Ensure the private key is a supported format (RSA PEM, PKCS#8) with correct newlines; convert if needed with `openssl`.
- Rotate to a fresh, non-deleted service account key.
Example fix
// before: private_key pasted into YAML, newlines literal
private_key: "-----BEGIN PRIVATE KEY-----\n...broken"
// after: load from the JSON key file so real newlines are preserved
let sa: ServiceAccount = serde_json::from_str(&std::fs::read_to_string("sa-key.json")?)?; Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the private key parses before token exchange
const key = sa.private_key;
if (!key || !key.includes('-----BEGIN') || !key.includes('\\n') === false && key.split('\n').length < 2) {
throw new Error('service account private_key malformed');
} Type guard
function hasValidPrivateKey(sa) { return typeof sa.private_key === 'string' && sa.private_key.startsWith('-----BEGIN') && sa.private_key.includes('END'); } Try / catch
try { await getOAuth2Token(sa); } catch (e) { console.error('JWT/token exchange failed:', e); throw new Error('Check service-account private_key format and freshness'); } Prevention
- Always load the service-account JSON via a parser; never paste private_key into YAML/env with mangled newlines
- Rotate and re-download keys instead of reusing old ones
- Log the inner Debug error from {e:?} to distinguish key vs serialization failures
When it happens
Trigger: Calling `ServiceAccount::get_oauth2_token` where `encode_jwt(&claims, &self.private_key)` fails: malformed/unsupported PEM private key, JSON serialization failure of the claims, or an encoding library error.
Common situations: A service-account JSON whose `private_key` contains unescaped newlines (copy-pasted or YAML-mangled), a key not in PKCS#8/RSA format, or an expired/rotated service account key.
Related errors
- Failed to auth - system_default strategy did not resolve suc
- Failed to load GCP creds project ID (failed to resolve): try
- `gh {}` failed: {}
- options.project_id is required when using API key auth with
- Failed to resolve {}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/57c13acb7bc5fcc0.
Report an issue: GitHub.