usebruno/bruno · error · Error

${response.error}

Error message

${response.error}

What it means

Thrown by handleOAuth2Response inside the renderer:fetch-oauth2-credentials flow when the token endpoint response carries an `.error` field but no `.debugInfo`. This is a non-recoverable OAuth2 error surfaced from the identity provider (e.g. invalid_grant, invalid_client, bad_verification_code). Responses with debugInfo are passed through so callers can retry with diagnostics.

Source

Thrown at packages/bruno-electron/src/ipc/collection.js:2013

            processEnvVars,
            promptVariables
          });
          let refreshRequestForConfig = { ...requestCopy, url: interpolatedRefreshUrl };
          certsAndProxyConfigForRefreshUrl = await getCertsAndProxyConfig({
            collectionUid,
            collection,
            request: refreshRequestForConfig,
            envVars,
            runtimeVariables,
            processEnvVars,
            collectionPath,
            globalEnvironmentVariables
          });
        }

        const handleOAuth2Response = (response) => {
          if (response.error && !response.debugInfo) {
            throw new Error(response.error);
          }
          return response;
        };

        switch (grantType) {
          case 'authorization_code':
            interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars);
            return await getOAuth2TokenUsingAuthorizationCode({
              request: requestCopy,
              collectionUid,
              forceFetch: true,
              certsAndProxyConfigForTokenUrl,
              certsAndProxyConfigForRefreshUrl
            }).then(handleOAuth2Response);

          case 'client_credentials':
            interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars);
            return await getOAuth2TokenUsingClientCredentials({

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Re-trigger the authorization_code flow — codes are single-use and short-lived.
  2. Confirm clientId, clientSecret, and token URL match the IdP app registration.
  3. Verify the redirect URI sent matches what is registered with the provider.
  4. If using refresh_token, prompt the user to re-authenticate when the token has been revoked.
  5. Read response.error verbatim — it is the IdP's RFC 6749 error code (e.g. invalid_grant).
Defensive patterns

Strategy: try-catch

Type guard

/** @typedef {{ error?: string, debugInfo?: unknown, access_token?: string }} OAuth2Response */
/** @param {OAuth2Response} r @returns {r is { error: string }} */
function isOAuth2ErrorResponse(r) {
  return !!r && typeof r.error === 'string' && !r.debugInfo;
}

Try / catch

try {
  const token = await ipcRenderer.invoke('renderer:fetch-oauth2-credentials', { itemUid, request, collection });
  return token;
} catch (err) {
  // err.message is the IdP's RFC 6749 error code (e.g. 'invalid_grant')
  if (/invalid_grant|expired/.test(err.message)) {
    // re-authenticate the user
  } else if (/invalid_client/.test(err.message)) {
    // surface a credentials-config error
  }
  throw err;
}

Prevention

When it happens

Trigger: Any OAuth2 grant (authorization_code, refresh_token, client_credentials, password) where the provider returns `{ error: '...' }` without a debug payload — typically expired codes, revoked refresh tokens, redirect URI mismatch, or wrong client credentials.

Common situations: Auth code used after expiry (10-minute window), refresh token revoked out-of-band, clock skew against the IdP, client secret rotated but not updated, redirect URI not whitelisted.

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/f078d395e05a99c3. Report an issue: GitHub.