{"record":{"id":"0ed8abffc55fdd1d","repo":"mastra-ai/mastra","slug":"platform-api-request-did-not-return-a-redirect","errorCode":null,"errorMessage":"Platform API request did not return a redirect.","messagePattern":"Platform API request did not return a redirect\\.","errorType":"http","errorClass":"PlatformApiError","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/platform/api-client.ts","lineNumber":95,"sourceCode":"    const response = await this.#send(method, path, undefined, options, 'manual');\n    if (response.status >= 300 && response.status < 400) {\n      const location = response.headers.get('location');\n      if (location) return location;\n    }\n    if (!response.ok) {\n      const message = redact(await extractError(response), this.#accessToken);\n      const retryAfterSeconds = parseRetryAfter(response.headers.get('retry-after'));\n      logPlatformError('Platform API redirect request failed', {\n        method,\n        path,\n        status: response.status,\n        retryAfterSeconds,\n        message,\n      });\n      throw new PlatformApiError(message, response.status, retryAfterSeconds);\n    }\n    logPlatformError('Platform API request did not return a redirect', { method, path, status: response.status });\n    throw new PlatformApiError('Platform API request did not return a redirect.', response.status);\n  }\n\n  async #send(\n    method: string,\n    path: string,\n    body?: unknown,\n    options?: { signal?: AbortSignal; actingUserId?: string },\n    redirect?: RequestInit['redirect'],\n  ): Promise<Response> {\n    const headers: Record<string, string> = {\n      accept: 'application/json',\n      authorization: `Bearer ${this.#accessToken}`,\n    };\n    // Acting end-user for platform GitHub writes: the platform resolves this\n    // user's GitHub OAuth connection (org-scoped) so issues/PRs are authored\n    // by the human instead of the App bot. Ignored by older platforms.\n    if (options?.actingUserId) {\n      headers['x-acting-user-id'] = options.actingUserId;","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/platform/api-client.ts#L77-L113","documentation":"PlatformApiError thrown by PlatformApiClient.requestRedirect (api-client.ts:95) when an HTTP call expected to return a 3xx redirect (fetched with redirect: 'manual') instead returned a successful non-redirect response. The client uses requestRedirect for endpoints whose success contract is a Location header (e.g. OAuth/browser redirect flows), so a 2xx response with no Location header is treated as a protocol violation rather than a result. The response's real status is preserved on the error.","triggerScenarios":"Calling client.requestRedirect(method, path) where the server responds 200/204 (or any 2xx) without a 3xx status or Location header — e.g. the endpoint was changed to return JSON instead of redirecting, a proxy/gateway strips the 3xx, or the wrong path is used so a normal endpoint answers instead of the redirect endpoint.","commonSituations":"Platform/API version mismatch where the redirect endpoint no longer exists and a default handler responds 200; an auth or GitHub App installation URL flow pointed at a JSON API route; a corporate proxy or load balancer rewriting redirects into 200 responses; typos in the path passed to requestRedirect.","solutions":["Verify the path passed to requestRedirect is the platform endpoint that issues redirects (e.g. OAuth authorize/install URL), not a JSON API route.","Check that the platform server version supports the redirect endpoint; upgrade platform or client if there is a version mismatch.","Inspect intermediate proxies/gateways that may convert 3xx into 200 and disable redirect rewriting for this route.","If a JSON response is actually expected, use client.request() instead of requestRedirect().","Catch PlatformApiError and inspect error.status to distinguish a 200-with-no-redirect from an actual HTTP failure."],"exampleFix":"// before: treating any endpoint as a redirect endpoint\nconst url = await client.requestRedirect('POST', '/api/agents');\n\n// after: use the redirect endpoint for redirect flows, request() for JSON\nconst url = await client.requestRedirect('POST', `/api/github/installations/${installationId}/install-url`);","handlingStrategy":"try-catch","validationCode":"// No client-side pre-check possible; ensure the path is the documented redirect endpoint\nconst REDIRECT_ENDPOINTS = ['/github/install-url', '/oauth/authorize'];\nif (!REDIRECT_ENDPOINTS.some((e) => path.startsWith(e))) {\n  throw new Error(`${path} is not a redirect endpoint; use client.request()`);\n}","typeGuard":"function isRedirectStatus(status: number): boolean {\n  return status >= 300 && status < 400;\n}","tryCatchPattern":"try {\n  const location = await client.requestRedirect('GET', path);\n} catch (err) {\n  if (err instanceof PlatformApiError && err.status >= 200 && err.status < 300) {\n    // Endpoint returned 2xx without a Location header: wrong endpoint or\n    // server/proxy stripped the redirect. Fall back or surface a clear message.\n  }\n  throw err;\n}","preventionTips":["Only call requestRedirect on endpoints documented to return 3xx + Location.","Use request() for JSON-returning endpoints.","Test redirect flows against the actual platform version you deploy against.","Check proxies/load balancers for redirect-rewriting behavior."],"tags":["http","redirect","api-client","platform-api"],"backgroundTag":"expected-redirect-not-received","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}