discordjs/discord.js · error · Error

JSON.stringify(response)

Error message

JSON.stringify(response)

What it means

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.

Source

Thrown at packages/rpc/src/client.ts:375

		}

		const response = await fetch(`${RouteBases.api}${Routes.oauth2TokenExchange()}`, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/x-www-form-urlencoded',
			},
			body: new URLSearchParams(jsonBody),
			...options,
		});

		if (!response.ok) {
			throw new Error(response.statusText);
		}

		const data = (await response.json()) as RESTPostOAuth2AccessTokenResult;

		if (!('access_token' in data)) {
			throw new Error(JSON.stringify(response));
		}

		return data.access_token;
	}

	/**
	 * Authenticate
	 *
	 * @param accessToken - access token
	 */
	public async authenticate(accessToken: string, options?: RequestOptions): Promise<this> {
		const { application, user } = await this.request(RPCCommands.Authenticate, { access_token: accessToken }, options);
		this.accessToken = accessToken;
		this.application = application;
		this.user = user;
		this.emit(Events.ApplicationReady);
		return this;
	}

View on GitHub (pinned to a81ed8a306)

Solutions

  1. Obtain a fresh authorization code and retry the exchange
  2. Inspect the actual response body (catch and re-fetch) to see the error field Discord returned
  3. Verify client_id, client_secret, grant_type, and redirect_uri exactly match the authorize step

Example fix

// before
try { await client.login({ clientId, clientSecret, scopes }); }
catch (e) { console.log(e.message); } // prints serialized Response
// after
try { await client.login({ clientId, clientSecret, scopes }); }
catch (e) { console.error('No access_token in token response — check code freshness and grant params'); }
Defensive patterns

Strategy: try-catch

Type guard

function hasAccessToken(d: unknown): d is { access_token: string } {
  return typeof d === 'object' && d !== null && 'access_token' in d;
}

Try / catch

try {
  await client.login({ clientId, clientSecret, scopes });
} catch (err) {
  // library stringifies the Response; treat as 'token missing in response'
  console.error('Token response lacked access_token — request a fresh authorization code');
}

Prevention

When it happens

Trigger: Discord returns 200 with an error-shaped JSON body (e.g. { error: 'invalid_grant' }) or an unexpected body during the token exchange in login().

Common situations: Reusing an already-consumed authorization code (invalid_grant), scope/redirect mismatch returning an error body with 200, or a proxy stripping the body.

Related errors


AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30). Data as JSON: /api/errors/2e85afde19a17f3b. Report an issue: GitHub.