gitbutlerapp/gitbutler · error · HttpStatusError

Failed to verify Bitbucket repository access

Error message

Failed to verify Bitbucket repository access

What it means

Fallback error from but-bitbucket's list_checks_for_ref: after a 404 on the commit-statuses endpoint, the client re-probes GET /repositories/{workspace}/{repo_slug} to distinguish 'reference not found' from 'repository inaccessible'. When that probe returns a status outside 401/403/404 (those get richer classification via classify_repository_access_error), the raw status is wrapped in HttpStatusError with this generic context. In practice it indicates an unexpected condition on Bitbucket's side or the network path: a 5xx outage, 429 rate limit, or an intermediary such as a proxy.

Source

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

        );
        let response = self.client.get(&url).send().await?;
        let status = response.status();
        if status == reqwest::StatusCode::NOT_FOUND {
            let repository_status = self.repository_status(workspace, repo_slug).await?;
            if repository_status.is_success() {
                return Ok(None);
            }
            if matches!(
                repository_status,
                reqwest::StatusCode::UNAUTHORIZED
                    | reqwest::StatusCode::FORBIDDEN
                    | reqwest::StatusCode::NOT_FOUND
            ) {
                return Err(self
                    .classify_repository_access_error(repository_status, workspace, repo_slug)
                    .await);
            }
            return Err(anyhow::Error::new(HttpStatusError {
                status: repository_status,
            })
            .context("Failed to verify Bitbucket repository access"));
        }
        if matches!(
            status,
            reqwest::StatusCode::UNAUTHORIZED | reqwest::StatusCode::FORBIDDEN
        ) {
            return Err(self
                .classify_repository_access_error(status, workspace, repo_slug)
                .await);
        }
        if !status.is_success() {
            bail!("Bitbucket request failed: {status}");
        }

        let page: Paginated<BitbucketApiBuildStatus> = response.json().await?;
        let mut statuses = page.values;

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Check https://status.bitbucketcloud.net for an ongoing incident when the status is 5xx
  2. Back off and retry - 429 responses carry Retry-After; wait that long before re-running
  3. Inspect proxy/firewall configuration if the status looks like 502/503 from an intermediary
  4. Re-run with tracing/debug logging enabled to capture the exact status code that reached this branch
Defensive patterns

Strategy: retry

Type guard

fn is_transient_http_error(err: &anyhow::Error) -> bool {
    matches!(
        err.downcast_ref::<HttpStatusError>().map(|e| e.status),
        Some(s) if s.is_server_error() || s == reqwest::StatusCode::TOO_MANY_REQUESTS
    )
}

Try / catch

let mut attempt = 0u32;
loop {
    match client.list_checks_for_ref(ws, slug, reference).await {
        Ok(statuses) => break Ok(statuses),
        Err(err) if is_transient_http_error(&err) && attempt < 3 => {
            tokio::time::sleep(std::time::Duration::from_secs(2u64.pow(attempt))).await;
            attempt += 1;
        }
        Err(err) => break Err(err),
    }
}

Prevention

When it happens

Trigger: list_checks_for_ref gets a 404 for the ref, then the repository probe returns 429 or 5xx because of burst polling or a Bitbucket incident; a corporate proxy answers 502/503; a rare non-classified 4xx from the repository endpoint.

Common situations: CI jobs polling build checks in tight loops tripping rate limits; Bitbucket Cloud status-page incidents; proxied or NATed egress environments rewriting responses.

Related errors


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