gitbutlerapp/gitbutler · error

Failed to fetch repository

Error message

Failed to fetch repository: {status} - {error_text}

What it means

Thrown by fetch_repo when the GET for repository metadata returns a non-success status. The message includes the HTTP status and Bitbucket's response body. Notably, if the failure is an access problem this path can instead be pre-empted by classify_repository_access_error in callers like list_checks_for_ref; this bail fires for other non-success statuses.

Solutions

  1. Verify workspace and repo-slug spelling and that the repository still exists
  2. Check the Bitbucket token is valid and has read access to the repository
  3. Handle 5xx with a retry/backoff
  4. Use the repository access error classifier for 401/403/404 cases to produce a clearer user-facing message

Example fix

// before
let repo = client.fetch_repo(workspace, repo_slug).await?;
// after
let repo = client.fetch_repo(workspace, repo_slug).await
    .map_err(|e| anyhow::anyhow!("Bitbucket repo {workspace}/{repo_slug}: {e:#}"))?;
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(!workspace.is_empty() && !repo_slug.is_empty(), "workspace/slug required");
// optionally probe access first
let _ = client.fetch_repo_permission(workspace, repo_slug).await?;

Try / catch

match client.fetch_repo(ws, slug).await {
    Err(e) if e.to_string().contains("404") => anyhow::bail!("repo {ws}/{slug} not found — check spelling"),
    Err(e) if e.to_string().contains("401") || e.to_string().contains("403") => anyhow::bail!("insufficient access: {e}"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling fetch_repo with a workspace/repo_slug that does not exist (404), with an invalid token (401), with a token lacking read access (403), or during a Bitbucket outage (5xx).

Common situations: Typo'd workspace or repository slug; repository renamed or moved; app password rotated/expired; private repo accessed with a public-scoped token.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/8842633f4a9feaa1. Report an issue: GitHub.

Appendix: source

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

            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            bail!("Failed to decline pull request: {status} - {error_text}");
        }
        Ok(())
    }

    pub async fn fetch_repo(&self, workspace: &str, repo_slug: &str) -> Result<BitbucketRepo> {
        let url = format!(
            "{}/repositories/{}/{}",
            self.base_url,
            urlencoding::encode(workspace),
            urlencoding::encode(repo_slug),
        );
        let response = self.client.get(&url).send().await?;
        if !response.status().is_success() {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            bail!("Failed to fetch repository: {status} - {error_text}");
        }
        let repo: BitbucketApiRepository = response.json().await?;

        // The caller's permission level lives behind a separate endpoint.
        let permission = self
            .fetch_repo_permission(workspace, repo_slug)
            .await
            .ok()
            .flatten();

        Ok(BitbucketRepo {
            is_fork: repo.parent.is_some(),
            is_private: repo.is_private,
            permission,
        })
    }

    /// Resolve the authenticated user's permission (`admin`/`write`/`read`) on a repo.

View on GitHub (pinned to 58e5313667)