gitbutlerapp/gitbutler · error · HttpStatusError

Bitbucket repository '{workspace}/{repo_slug}' is inaccessib

Error message

Bitbucket repository '{workspace}/{repo_slug}' is inaccessible to this token, or the token is missing required scope `read:repository:bitbucket`

What it means

Terminal message of classify_repository_access_error in but-bitbucket: the repository endpoint denied access and the /user probe could not narrow the cause (a successful /user proves the token itself is valid; a failed one gets its own context). The remaining explanations: this token cannot see {workspace}/{repo_slug}, or it lacks the read:repository:bitbucket scope required by GET /repositories/{ws}/{slug}. Bitbucket deliberately hides missing-scope from no-access, so both are listed.

Source

Thrown at crates/but-bitbucket/src/client.rs:614

        workspace: &str,
        repo_slug: &str,
    ) -> anyhow::Error {
        if let Err(err) = self.get_authenticated().await {
            if let Some(http_err) = err.downcast_ref::<HttpStatusError>() {
                return match http_err.status {
                    reqwest::StatusCode::UNAUTHORIZED => {
                        err.context("Bitbucket credentials are invalid or expired")
                    }
                    reqwest::StatusCode::FORBIDDEN => err.context(
                        "Bitbucket API token is missing required scope `read:user:bitbucket`",
                    ),
                    _ => err.context("Failed to verify Bitbucket credentials"),
                };
            }
            return err.context("Failed to verify Bitbucket credentials");
        }

        anyhow::Error::new(HttpStatusError { status }).context(format!(
            "Bitbucket repository '{workspace}/{repo_slug}' is inaccessible to this token, or the token is missing required scope `read:repository:bitbucket`"
        ))
    }
}

pub(crate) fn resolve_account(
    preferred_account: Option<&crate::BitbucketAccountIdentifier>,
    storage: &but_forge_storage::Controller,
) -> Result<crate::BitbucketAccountIdentifier, anyhow::Error> {
    let known_accounts = crate::token::list_known_bitbucket_accounts(storage)?;
    let Some(default_account) = known_accounts.first() else {
        bail!(
            "No authenticated Bitbucket users found.\nRun 'but config forge auth' to authenticate with Bitbucket."
        );
    };
    let account = if let Some(account) = preferred_account {
        if known_accounts.contains(account) {
            account

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Grant read:repository:bitbucket to the token (plus read:user:bitbucket), then re-add it
  2. Confirm workspace and slug exactly as in the browser URL and retype them
  3. Check the token's account is a member of the workspace that owns the repository
  4. Test the raw endpoint: curl -s -o /dev/null -w '%{http_code}' -H 'Authorization: Bearer $TOKEN' https://api.bitbucket.org/2.0/repositories/<ws>/<slug>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight right after token entry: the repository endpoint must answer 200
curl -s -o /dev/null -w '%{http_code}' \
  -H 'Authorization: Bearer $TOKEN' \
  https://api.bitbucket.org/2.0/repositories/<workspace>/<repo_slug>
// 200 = access OK; 401/403 = scope or auth problem; 404 = wrong slug or no access

Type guard

fn is_repository_access_error(err: &anyhow::Error) -> bool {
    err.chain().any(|c| c.to_string().contains("read:repository:bitbucket"))
}

Try / catch

if let Err(err) = client.list_checks_for_ref(ws, slug, ref_).await {
    if is_repository_access_error(&err) {
        // stop the onboarding flow and ask for scope fix / correct slug
        return Err(err.context("fix token scopes or workspace/slug, then retry"));
    }
    return Err(err);
}

Prevention

When it happens

Trigger: Fetching checks or PR data with a token that has no access to the repository (404 masquerading as denial); a token created without read:repository:bitbucket (403); workspace or repo_slug typo; private repository in a workspace the token's account does not belong to.

Common situations: Workspace-scoped API keys; repository renamed after its URL was copied; user has several workspaces and the token was issued under the wrong one.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/c06e040c8d210143. Report an issue: GitHub.