{"record":{"id":"55e08628edddd076","repo":"mastra-ai/mastra","slug":"failed-to-get-netlify-ai-gateway-token-response","errorCode":null,"errorMessage":"Failed to get Netlify AI Gateway token: ${response.status} ${error}","messagePattern":"Failed to get Netlify AI Gateway token: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/llm/model/gateways/netlify.ts","lineNumber":125,"sourceCode":"\n    // Check cache first\n    const cached = (await this.tokenCache.get(cacheKey)) as CachedToken | undefined;\n    if (cached && cached.expiresAt > Date.now() / 1000 + 60) {\n      // Return cached token if it won't expire in the next minute\n      return { token: cached.token, url: cached.url };\n    }\n\n    // Fetch new token\n    const response = await fetch(`https://api.netlify.com/api/v1/sites/${siteId}/ai-gateway/token`, {\n      method: 'GET',\n      headers: {\n        Authorization: `Bearer ${netlifyToken}`,\n      },\n    });\n\n    if (!response.ok) {\n      const error = await response.text();\n      throw new Error(`Failed to get Netlify AI Gateway token: ${response.status} ${error}`);\n    }\n\n    const tokenResponse = (await response.json()) as NetlifyTokenResponse;\n\n    // Cache the token - InMemoryServerCache will handle the TTL\n    await this.tokenCache.set(cacheKey, {\n      token: tokenResponse.token,\n      url: tokenResponse.url,\n      expiresAt: tokenResponse.expires_at,\n    });\n\n    return { token: tokenResponse.token, url: tokenResponse.url };\n  }\n\n  /**\n   * Get cached token or fetch a new site-specific AI Gateway token from Netlify\n   */\n  async getApiKey(modelId: string): Promise<string> {","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/llm/model/gateways/netlify.ts#L107-L143","documentation":"getOrFetchToken fetches a gateway token from the Netlify API using the NETLIFY_TOKEN bearer credentials. When the HTTP response is not ok, it throws a plain Error containing the HTTP status and response body text. This error is usually wrapped by NETLIFY_GATEWAY_TOKEN_ERROR (1391/1395) at call sites.","triggerScenarios":"The Netlify token endpoint returns a non-2xx status — 401 for invalid/expired NETLIFY_TOKEN, 404 for a bad site ID, 5xx for Netlify-side issues — during getOrFetchToken.","commonSituations":"Rotated or revoked Netlify access token still deployed; token lacking permission for AI Gateway; site deleted or site ID typo; Netlify API incident.","solutions":["Check the status code in the message: 401/403 → fix NETLIFY_TOKEN; 404 → fix NETLIFY_SITE_ID; 5xx → retry later","Regenerate the Netlify personal access token and update the environment secret","Validate the site ID against `netlify sites:list`","Inspect the response body text in the message for Netlify's specific error detail"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight: verify token validity before use\nconst res = await fetch('https://api.netlify.com/api/v1/user', {\n  headers: { Authorization: `Bearer ${process.env.NETLIFY_TOKEN}` },\n});\nif (!res.ok) throw new Error(`NETLIFY_TOKEN invalid: HTTP ${res.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  const token = await gateway.getApiKey('netlify/openai/gpt-4o');\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (/status: (5\\d\\d|429)/.test(msg)) {\n    // transient: retry with backoff\n  } else if (/status: (401|403)/.test(msg)) {\n    // credentials: fix NETLIFY_TOKEN, do not blind-retry\n  }\n  throw e;\n}","preventionTips":["Use fine-grained tokens with AI Gateway permissions and long expiry","Distinguish retryable (5xx/429) from non-retryable (401/403/404) statuses before retrying","Watch Netlify status for API incidents"],"tags":["netlify","http","authentication","api-error"],"backgroundTag":"http-401-unauthorized","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}