BloopAI/vibe-kanban · error

github token exchange failed: {detail}

Error message

github token exchange failed: {detail}

What it means

During the GitHub OAuth code-for-token exchange, GitHub responded with an error variant in its token response (e.g. bad_verification_code, redirect_uri mismatch) instead of an access token. The provider surfaces GitHub's own error (or its description) in the message.

Source

Thrown at crates/remote/src/auth/provider.rs:222

        match response.json::<GitHubTokenResponse>().await? {
            GitHubTokenResponse::Success {
                access_token,
                scope,
                token_type,
            } => Ok(AuthorizationGrant {
                access_token: SecretString::new(access_token.into()),
                token_type,
                scopes: Self::parse_scopes(scope),
                refresh_token: None,
                expires_in: None,
                id_token: None,
            }),
            GitHubTokenResponse::Error {
                error,
                error_description,
            } => {
                let detail = error_description.unwrap_or_else(|| error.clone());
                anyhow::bail!("github token exchange failed: {detail}")
            }
        }
    }

    async fn fetch_user(&self, access_token: &SecretString) -> Result<ProviderUser> {
        let bearer = format!("Bearer {}", access_token.expose_secret());

        let user: GitHubUser = self
            .client
            .get("https://api.github.com/user")
            .header("Accept", "application/vnd.github+json")
            .header("Authorization", &bearer)
            .send()
            .await?
            .error_for_status()?
            .json()
            .await?;

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Restart the OAuth flow to obtain a fresh authorization code
  2. Verify client_id, client_secret, and redirect_uri match between the auth URL and token request
  3. Ensure the code is exchanged exactly once and immediately after redirect
  4. Check GitHub OAuth app settings in the developer portal

Example fix

// before
// exchanging a code twice
let t1 = provider.exchange_code(&code).await?;
let t2 = provider.exchange_code(&code).await?; // github token exchange failed: bad_verification_code
// after
let t = provider.exchange_code(&code).await?; // exchange exactly once
Defensive patterns

Strategy: retry

Try / catch

match provider.exchange_code(&code).await { Err(e) if e.to_string().starts_with("github token exchange failed") => restart_oauth_flow(), // codes are single-use; never retry with same code
 other => other? }

Prevention

When it happens

Trigger: exchange_code() called with an expired, already-used, or invalid authorization code; GitHub returns error/error_description in the token response body.

Common situations: User took too long to authorize so the code expired; code replayed on a second exchange; mismatched client_id/client_secret or redirect_uri between the authorize and token requests; clock skew invalidating signed requests.

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/c8c740dddf635eed. Report an issue: GitHub.