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
- Check https://status.bitbucketcloud.net for an ongoing incident when the status is 5xx
- Back off and retry - 429 responses carry Retry-After; wait that long before re-running
- Inspect proxy/firewall configuration if the status looks like 502/503 from an intermediary
- 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
- Cache check-query results instead of polling in tight loops; add jitter between polls
- Watch Bitbucket's status feed and pause automation during incidents
- Distinguish 5xx/429 from 4xx in logs so transient vs permanent failures are visible
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
- Failed to create pull request: {status} - {error_text}
- Bitbucket repository '{workspace}/{repo_slug}' is inaccessib
- Failed to persist action: {e}
- Failed to list actions: {e}
- CliInstallCancelled
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/ed5e9a26543f75a7.
Report an issue: GitHub.