gitbutlerapp/gitbutler · error

No GitButler token available. Log-in to use the GitButler Op

Error message

No GitButler token available. Log-in to use the GitButler OpenAI provider

What it means

OpenAI counterpart of the Anthropic token error, thrown by OpenAiProvider::gitbutler_proxied_creds in crates/but-llm/src/openai.rs when secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, Namespace::BuildKind) returns None. The GitButler-proxied OpenAI provider requires the logged-in user's access token to route requests through GitButler's proxy.

Source

Thrown at crates/but-llm/src/openai.rs:84

        }
    }

    /// Configure a custom endpoint if set in the provider, if any.
    fn configure_custom_endpoint(&self, config: OpenAIConfig) -> OpenAIConfig {
        if let Some(custom_endpont) = &self.custom_endpoint {
            config.with_api_base(custom_endpont)
        } else {
            config
        }
    }

    pub fn credentials_kind(&self) -> CredentialsKind {
        self.credentials.0.clone()
    }

    fn gitbutler_proxied_creds() -> Result<(CredentialsKind, Sensitive<String>)> {
        let creds = secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, secret::Namespace::BuildKind)?
            .ok_or(anyhow::anyhow!(
                "No GitButler token available. Log-in to use the GitButler OpenAI provider"
            ))?;
        Ok((CredentialsKind::GitButlerProxied, creds))
    }

    fn openai_own_key_creds() -> Result<(CredentialsKind, Sensitive<String>)> {
        let creds = secret::retrieve(AI_OPENAI_SECRET_HANDLE, secret::Namespace::Global)?.ok_or(
            anyhow::anyhow!(
                "No OpenAI own key configured. Add this through the GitButler settings"
            ),
        )?;
        Ok((CredentialsKind::OwnOpenAiKey, creds))
    }

    fn openai_env_var_creds() -> Result<(CredentialsKind, Sensitive<String>)> {
        let creds = Sensitive(
            std::env::var_os("OPENAI_API_KEY")
                .ok_or(anyhow::anyhow!(

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Log in via the GitButler desktop app to populate the access token secret.
  2. Or add an OpenAI API key in GitButler settings (OwnOpenAiKey path).
  3. Or export OPENAI_API_KEY for the env-var credential path.
  4. Pass preferred_creds = None to let the provider fall back across all three sources.
Defensive patterns

Strategy: fallback

Validate before calling

let has_token = secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, secret::Namespace::BuildKind).ok().flatten().is_some();
if !has_token { /* choose own-key or env-var credentials */ }

Type guard

fn can_use_proxied_openai() -> bool {
    secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, secret::Namespace::BuildKind)
        .ok()
        .flatten()
        .is_some()
}

Try / catch

let provider = match OpenAiProvider::with(Some(CredentialsKind::GitButlerProxied), model) {
    Some(p) => p,
    None => OpenAiProvider::with(None, model).expect("no OpenAI credentials"),
};

Prevention

When it happens

Trigger: Constructing OpenAiProvider with preferred_creds = Some(CredentialsKind::GitButlerProxied) while not logged in; the no-preference fallback chain reaching proxied creds first when no other OpenAI credential exists.

Common situations: CLI/TUI usage without a prior desktop-app login; token cleared by logout or keychain reset; CI runners with no GitButler session.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/56a6680ace525c47. Report an issue: GitHub.