{"record":{"id":"d528d2dc6f2d7bc7","repo":"vercel/ai","slug":"cartesia-realtime-client-secret-response-did-not-i","errorCode":null,"errorMessage":"Cartesia realtime client secret response did not include a token.","messagePattern":"Cartesia realtime client secret response did not include a token\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cartesia/src/cartesia-realtime-model.ts","lineNumber":110,"sourceCode":"        ...this.config.headers(),\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        grants: { stt: true },\n        ...(expiresIn != null ? { expires_in: expiresIn } : {}),\n      }),\n    });\n\n    if (!response.ok) {\n      const text = await response.text();\n      throw new Error(\n        `Cartesia realtime client secret request failed: ${response.status} ${text}`,\n      );\n    }\n\n    const data = (await response.json()) as { token?: unknown };\n    if (typeof data.token !== 'string' || data.token.length === 0) {\n      throw new Error(\n        'Cartesia realtime client secret response did not include a token.',\n      );\n    }\n\n    const turnDetection = sessionConfig?.turnDetection;\n    const useTurnDetection =\n      turnDetection === undefined ||\n      (turnDetection !== null && turnDetection.type !== 'disabled');\n    const inputAudioFormat = sessionConfig?.inputAudioFormat;\n    const url = new URL(\n      useTurnDetection\n        ? `${this.config.baseURL}/stt/turns/websocket`\n        : `${this.config.baseURL}/stt/websocket`,\n    );\n    url.protocol = url.protocol === 'http:' ? 'ws:' : 'wss:';\n    url.searchParams.set('model', this.modelId);\n    url.searchParams.set(\n      'encoding',","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/vercel/ai/blob/69428b1f8b037e4d118fb4853428d5c4e620493c/packages/cartesia/src/cartesia-realtime-model.ts#L92-L128","documentation":"If the /access-token request succeeds (2xx) but the parsed JSON body does not contain a non-empty string token field, doCreateClientSecret throws. The client treats a missing/empty token as unusable — a client secret cannot be issued without it, so this indicates an unexpected success response shape.","triggerScenarios":"Cartesia returns 200 with a body lacking token (schema change, HTML error page served with 200, empty body, or a body keyed differently, e.g. { secret: ... }).","commonSituations":"Misconfigured baseURL pointing at a non-Cartesia endpoint that returns 200 HTML; authenticated but under-privileged key returning an empty success payload; API version drift.","solutions":["Log the raw response body to see what the endpoint actually returned under a 200 status.","Verify this.config.baseURL points to the genuine Cartesia API (https://api.cartesia.ai), not a proxy or wrong region URL.","Check your Cartesia account/plan includes realtime access-token issuance.","Upgrade @ai-sdk/cartesia in case the token response schema changed and the provider needs an update."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// Validate the endpoint returns JSON with a token before trusting it:\nconst res = await fetch(`${baseURL}/access-token`, { method: 'POST' });\nconst ct = res.headers.get('content-type') ?? '';\nif (!ct.includes('application/json')) console.error('Non-JSON response from /access-token — check baseURL');","typeGuard":"function hasToken(data: unknown): data is { token: string } {\n  return typeof data === 'object' && data !== null &&\n    'token' in data && typeof (data as { token: unknown }).token === 'string' &&\n    (data as { token: string }).token.length > 0;\n}","tryCatchPattern":"try {\n  return await model.doCreateClientSecret(options);\n} catch (e) {\n  if (/did not include a token/.test(String(e.message))) {\n    // verify baseURL/plan, then retry once\n    return retry(() => model.doCreateClientSecret(options), 1);\n  }\n  throw e;\n}","preventionTips":["Ensure baseURL is the real Cartesia API so 200 responses are genuine JSON token payloads.","Confirm your Cartesia plan/account can issue realtime access tokens.","Log the raw 200 body when this occurs to catch schema drift early."],"tags":["api-response","authentication","realtime"],"backgroundTag":"missing-field-in-api-response","analyzedSha":"69428b1f8b037e4d118fb4853428d5c4e620493c","analyzedAt":"2026-08-30T12:32:21.016Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}