{"record":{"id":"2e85afde19a17f3b","repo":"discordjs/discord.js","slug":"json-stringify-response","errorCode":null,"errorMessage":"JSON.stringify(response)","messagePattern":"JSON\\.stringify\\(response\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/rpc/src/client.ts","lineNumber":375,"sourceCode":"\t\t}\n\n\t\tconst response = await fetch(`${RouteBases.api}${Routes.oauth2TokenExchange()}`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t},\n\t\t\tbody: new URLSearchParams(jsonBody),\n\t\t\t...options,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(response.statusText);\n\t\t}\n\n\t\tconst data = (await response.json()) as RESTPostOAuth2AccessTokenResult;\n\n\t\tif (!('access_token' in data)) {\n\t\t\tthrow new Error(JSON.stringify(response));\n\t\t}\n\n\t\treturn data.access_token;\n\t}\n\n\t/**\n\t * Authenticate\n\t *\n\t * @param accessToken - access token\n\t */\n\tpublic async authenticate(accessToken: string, options?: RequestOptions): Promise<this> {\n\t\tconst { application, user } = await this.request(RPCCommands.Authenticate, { access_token: accessToken }, options);\n\t\tthis.accessToken = accessToken;\n\t\tthis.application = application;\n\t\tthis.user = user;\n\t\tthis.emit(Events.ApplicationReady);\n\t\treturn this;\n\t}","sourceCodeStart":357,"sourceCodeEnd":393,"githubUrl":"https://github.com/discordjs/discord.js/blob/a81ed8a306d37fdc746e26a634b6a42164ba2c8c/packages/rpc/src/client.ts#L357-L393","documentation":"After a 200 response, authorize() parses the JSON and throws JSON.stringify(response) if the body has no access_token field. The error message is the serialized Response object, which is nearly useless for debugging — the token endpoint replied successfully but not with a token payload.","triggerScenarios":"Discord returns 200 with an error-shaped JSON body (e.g. { error: 'invalid_grant' }) or an unexpected body during the token exchange in login().","commonSituations":"Reusing an already-consumed authorization code (invalid_grant), scope/redirect mismatch returning an error body with 200, or a proxy stripping the body.","solutions":["Obtain a fresh authorization code and retry the exchange","Inspect the actual response body (catch and re-fetch) to see the error field Discord returned","Verify client_id, client_secret, grant_type, and redirect_uri exactly match the authorize step"],"exampleFix":"// before\ntry { await client.login({ clientId, clientSecret, scopes }); }\ncatch (e) { console.log(e.message); } // prints serialized Response\n// after\ntry { await client.login({ clientId, clientSecret, scopes }); }\ncatch (e) { console.error('No access_token in token response — check code freshness and grant params'); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function hasAccessToken(d: unknown): d is { access_token: string } {\n  return typeof d === 'object' && d !== null && 'access_token' in d;\n}","tryCatchPattern":"try {\n  await client.login({ clientId, clientSecret, scopes });\n} catch (err) {\n  // library stringifies the Response; treat as 'token missing in response'\n  console.error('Token response lacked access_token — request a fresh authorization code');\n}","preventionTips":["Never reuse authorization codes (invalid_grant returns token-less bodies)","Log the raw token endpoint body during development to see Discord's error field","Match grant_type and redirect_uri exactly with the authorize request"],"tags":["oauth","http","response-parsing"],"backgroundTag":"unexpected-response-body","analyzedSha":"a81ed8a306d37fdc746e26a634b6a42164ba2c8c","analyzedAt":"2026-08-30T04:07:22.193Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}