decolua/9router · error
Vertex: failed to mint access token from Service Account JSO
Error message
Vertex: failed to mint access token from Service Account JSON
What it means
Thrown in VertexExecutor.execute (open-sse/executors/vertex.js:138) when refreshVertexToken fails to mint a Bearer access token from the stored Service Account JSON. Token minting (JWT assertion signed with the SA private key, exchanged at Google's OAuth2 token endpoint) is delegated to tokenRefresh.js; a null/empty accessToken result means the exchange did not produce a usable token.
Source
Thrown at open-sse/executors/vertex.js:138
async refreshCredentials(credentials, log) {
const saJson = parseVertexSaJson(credentials?.apiKey);
if (!saJson) return null;
const result = await refreshVertexToken(saJson, log);
if (!result) return null;
return { accessToken: result.accessToken, expiresAt: result.expiresAt };
}
async execute({ model, body, stream, credentials, signal, log, proxyOptions = null }) {
const saJson = parseVertexSaJson(credentials?.apiKey);
const adcJson = parseVertexAdcJson(credentials?.apiKey);
// SA JSON flow: mint Bearer token via JWT assertion (cached)
if (saJson) {
const result = await refreshVertexToken(saJson, log);
if (!result?.accessToken) throw new Error("Vertex: failed to mint access token from Service Account JSON");
credentials.accessToken = result.accessToken;
}
// ADC user credential flow: refresh Bearer token via Google OAuth2 token endpoint
if (adcJson) {
const result = await refreshGoogleToken(
adcJson.refresh_token,
adcJson.client_id,
adcJson.client_secret,
log
);
if (!result?.accessToken) throw new Error("Vertex: failed to refresh access token from ADC JSON (authorized_user)");
credentials.accessToken = result.accessToken;
}
// vertex-partner with raw key: auto-resolve project_id if not provided
if (this.provider === "vertex-partner" && !saJson && !adcJson && !credentials?.providerSpecificData?.projectId) {
const projectId = await resolveProjectId(credentials.apiKey);View on GitHub (pinned to 90b52e06ff)
Solutions
- Re-download a fresh Service Account JSON key from GCP IAM (Keys → Add key → JSON) and re-save it as the credential's apiKey, keeping the private_key newlines intact.
- Check connectivity/proxy to https://oauth2.googleapis.com/token — the mint request must reach Google.
- Verify the service account is enabled and the key is not expired/revoked in the GCP console.
- Check logs from refreshVertexToken (the log object passed in) for the underlying Google error (e.g. invalid_grant, invalid_scope) and fix accordingly.
Defensive patterns
Strategy: try-catch
Validate before calling
const sa = parseVertexSaJson(creds?.apiKey);
if (sa) {
const required = ["client_email", "private_key", "project_id"];
const missing = required.filter(k => !sa[k]);
if (missing.length) throw new Error(`SA JSON missing fields: ${missing.join(", ")}`);
} Type guard
function isValidSaJson(v) {
if (typeof v !== "string") return false;
try {
const j = JSON.parse(v);
return j.type === "service_account" && typeof j.private_key === "string" && j.private_key.includes("PRIVATE KEY") && !!j.client_email;
} catch { return false; }
} Try / catch
try {
await vertexChat(model, body);
} catch (e) {
if (/failed to mint access token from Service Account JSON/.test(e.message)) {
log.error("SA token mint failed — check key validity, clock skew, and oauth2.googleapis.com reachability");
await reauthFlow();
} else throw e;
} Prevention
- Re-download SA keys before expiry and rotate them proactively.
- Keep the SA JSON intact (preserve private_key newlines) when pasting/storing.
- Ensure server clocks are NTP-synced — skew breaks JWT assertions.
- Allow egress to oauth2.googleapis.com in firewalls/proxies.
When it happens
Trigger: execute() is called, credentials.apiKey parses as a Service Account JSON (parseVertexSaJson), refreshVertexToken(saJson, log) resolves to null or an object without accessToken — e.g. JWT signing failed (bad private_key), Google's token endpoint rejected the assertion (invalid_grant), the network call failed, or the SA key was revoked/disabled.
Common situations: Service account key was deleted or disabled in GCP IAM; the SA JSON was copied incompletely (truncated private_key, missing client_email); system clock skew invalidates the JWT iat/exp; outbound access to oauth2.googleapis.com is blocked by firewall/proxy; key file was re-encoded and newlines in private_key were mangled.
Related errors
- Vertex: failed to refresh access token from ADC JSON (author
- loadCodeAssist failed: HTTP ${response.status} ${errorText.s
- onboardUser HTTP ${response.status}: ${errorText.slice(0, 20
- No Codex access token available. Please re-authorize the con
- No GitHub access token available. Please re-authorize the co
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/6980021108531b1c.
Report an issue: GitHub.