Kuberwastaken/claurst · error · anyhow::Error

Bridge upload: server returned

Error message

Bridge upload: server returned {}

What it means

Within `refresh_mcp_token`, after loading the stored token, the code reads `existing.refresh_token`. If the stored `McpToken` has no refresh token (the provider did not issue one during the original exchange), this error is returned. Without a refresh token the library cannot silently renew the credentials.

Solutions

  1. Re-run `run_mcp_auth_flow` to obtain a fresh token that includes a refresh token.
  2. Check the provider's requirements: request the scopes needed for refresh tokens (e.g. offline_access) in the authorization URL.
  3. Verify the token exchange actually returns a refresh_token field for this provider/client.
  4. Until re-auth, treat the token as non-renewable: re-authenticate each time it expires.

Example fix

// before: auth_url scopes may omit refresh-eligible scope
// after: include offline access so a refresh token is issued
let auth_url = format!(
    "{}?response_type=code&client_id={}&redirect_uri={}&scope={} offline_access&state={}",
    auth_endpoint, client_id, redirect_uri, scopes, state
);
Defensive patterns

Strategy: fallback

Validate before calling

// before refreshing, check a refresh token is available
let can_refresh = get_mcp_token(server_name)
    .and_then(|t| t.refresh_token)
    .is_some();

Try / catch

match refresh_mcp_token(server, endpoint).await {
    Ok(t) => t,
    Err(e) if e.to_string().contains("has no refresh token") => {
        run_mcp_auth_flow(&session).await? // re-auth required
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The stored token for `server_name` exists but `refresh_token` is None — the original authorization/token exchange did not yield a refresh token, and now `get_valid_mcp_token` attempts a refresh.

Common situations: Provider that only issues refresh tokens with specific scopes (e.g. Google requires offline access) or for certain client types; the original flow stored a short-lived token without a refresh grant; older stored tokens created before refresh support was added.

Related errors


AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10). Data as JSON: /api/errors/fb3c755873e13072. Report an issue: GitHub.

Appendix: source

Thrown at src-rust/crates/bridge/src/lib.rs:630

        let resp = self
            .http
            .post(&url)
            .bearer_auth(token)
            .json(&body)
            .send()
            .await
            .context("Bridge upload: HTTP send failed")?;

        if !resp.status().is_success() {
            let status = resp.status().as_u16();
            warn!(
                session_id = %self.session_id,
                status,
                count = events.len(),
                "Bridge event upload failed"
            );
            anyhow::bail!("Bridge upload: server returned {}", status);
        }

        debug!(
            session_id = %self.session_id,
            count = events.len(),
            "Bridge events uploaded"
        );
        Ok(())
    }

    // -----------------------------------------------------------------------
    // Main poll loop
    // -----------------------------------------------------------------------

    /// Run the bridge poll loop until `cancel` is triggered or a fatal error
    /// occurs.
    ///
    /// On each iteration:

View on GitHub (pinned to b0637c97ec)