{"record":{"id":"54468f1eb263301b","repo":"mastra-ai/mastra","slug":"failed-to-fetch-connection-string-await-extrac","errorCode":null,"errorMessage":"Failed to fetch connection string — ${await extractError(res)}","messagePattern":"Failed to fetch connection string — (.+?)","errorType":"http","errorClass":"PlatformApiError","httpStatus":null,"severity":"error","filePath":"mastracode/mastra-factory/src/platform.ts","lineNumber":198,"sourceCode":"\n/** GET /v1/server/projects/:id/databases/:dbId/connection — only 200s when `ready`. */\nexport async function getDatabaseConnection({\n  token,\n  orgId,\n  projectId,\n  databaseId,\n}: {\n  token: string;\n  orgId: string;\n  projectId: string;\n  databaseId: string;\n}): Promise<DatabaseConnection> {\n  const res = await platformFetch(\n    `${MASTRA_PLATFORM_API_URL}/v1/server/projects/${encodeURIComponent(projectId)}/databases/${encodeURIComponent(databaseId)}/connection`,\n    { headers: authHeaders(token, orgId) },\n  );\n  if (!res.ok) {\n    throw new PlatformApiError(res.status, `Failed to fetch connection string — ${await extractError(res)}`);\n  }\n  return (await res.json()) as DatabaseConnection;\n}\n\n/**\n * Poll `getDatabaseStatus` until the database is `ready`.\n *\n * Each poll is bounded by the *remaining* overall budget via a per-request\n * `AbortSignal`, so a hung `platformFetch` can't blow past `timeoutMs`. When\n * an outer `signal` is supplied it composes with the per-request timeout —\n * whichever fires first aborts the in-flight request.\n *\n * @param intervalMs how often to poll (default 2s)\n * @param timeoutMs total budget (default 60s)\n */\nexport async function waitForDatabaseReady({\n  token,\n  orgId,","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/mastra-factory/src/platform.ts#L180-L216","documentation":"getDatabaseConnection calls GET /v1/server/projects/:id/databases/:dbId/connection, which only returns 200 once the database is `ready`. Any non-ok response becomes this PlatformApiError with the upstream status and the server's error text.","triggerScenarios":"Fetching the connection string before the database is ready (409/425-style response or 404), with an expired/invalid token (401), wrong ids (404), or a platform-side failure (5xx).","commonSituations":"Calling `connection` immediately after creation without waiting for `ready` status; stale token in a long script; copying the wrong databaseId; racing two CLI runs against the same database.","solutions":["Always await waitForDatabaseReady (status === 'ready') before fetching the connection string.","Re-authenticate if the token has expired, then retry the connection fetch.","Verify projectId/databaseId match the attached database for the given org.","Retry after a short delay if the status indicates the database is still transitioning."],"exampleFix":"// before\nconst conn = await getDatabaseConnection({ token, orgId, projectId, databaseId });\n// after\nawait waitForDatabaseReady({ token, orgId, projectId, databaseId });\nconst conn = await getDatabaseConnection({ token, orgId, projectId, databaseId });","handlingStrategy":"validation","validationCode":"// only fetch connection after the DB reports ready\nconst db = await waitForDatabaseReady({ token, orgId, projectId, databaseId });\nif (db.status !== 'ready') throw new Error(`Database not ready (${db.status}); cannot fetch connection yet.`);\nconst conn = await getDatabaseConnection({ token, orgId, projectId, databaseId });","typeGuard":"function isReady(db) { return db?.status === 'ready'; }","tryCatchPattern":"try {\n  return await getDatabaseConnection(opts);\n} catch (err) {\n  if (err instanceof PlatformApiError && (err.status === 404 || err.status === 409)) {\n    // DB not ready yet — wait then retry once\n    await waitForDatabaseReady(opts);\n    return getDatabaseConnection(opts);\n  }\n  throw err;\n}","preventionTips":["Always gate the connection fetch behind a successful waitForDatabaseReady.","Re-authenticate if scripts run longer than token lifetime.","Verify projectId/databaseId against the attach response rather than hand-copying.","Serialize provisioning steps; avoid concurrent CLI runs on the same database."],"tags":["http-error","platform-api","database-connection","race-condition"],"backgroundTag":"http-api-error","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}