diegosouzapw/OmniRoute · error

GitLab Duo token exchange failed

Error message

GitLab Duo token exchange failed: ${error}

What it means

Thrown when GitLab Duo's OAuth token endpoint answers the authorization-code exchange with a non-2xx status; the raw response body text is embedded so operators can see GitLab's OAuth error (invalid_grant, redirect_uri mismatch, expired code, revoked app). Fires when the PKCE exchange POST fails upstream, not on network errors (those reject the fetch itself).

Solutions

  1. Restart the flow if the code expired
  2. Confirm client id/secret and redirect_uri against the GitLab app
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at src/lib/oauth/providers/gitlab-duo.ts:72 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of diegosouzapw/OmniRoute@a179ffed5b (2026-08-25). Data as JSON: /api/errors/1272ce023bcf4d83. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/oauth/providers/gitlab-duo.ts:72

      code_verifier: codeVerifier,
    });

    if (config.clientSecret) {
      body.set("client_secret", config.clientSecret);
    }

    const response = await fetch(config.tokenUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        Accept: "application/json",
      },
      body,
    });

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`GitLab Duo token exchange failed: ${error}`);
    }

    return await response.json();
  },
  postExchange: async (tokens) => {
    const endpoints = buildGitLabOAuthEndpoints(GITLAB_DUO_CONFIG.baseUrl);
    const headers = {
      Authorization: `Bearer ${tokens.access_token}`,
      Accept: "application/json",
    };

    const userRes = await fetch(endpoints.userUrl, { headers });
    const userInfo = userRes.ok ? ((await userRes.json()) as Record<string, unknown>) : {};

    let directAccess = null;
    try {
      const directRes = await fetch(endpoints.directAccessUrl, {
        method: "POST",

View on GitHub (pinned to a179ffed5b)