gitbutlerapp/gitbutler · error · anyhow::Error

Failed to get merge request: {}

Error message

Failed to get merge request: {}

What it means

Thrown by GitLabClient::get_merge_request when GitLab's REST API answers GET /projects/:id/merge_requests/:iid with any non-2xx status. Only the status code is embedded; the response body is discarded, so you must map 401/403/404 yourself. Network/transport failures of the same call surface as a different error (the `?` on send()), and a JSON decode failure as yet another; this bail is strictly an HTTP-level rejection. On success the MR is additionally enriched with its source project (fork detection, SSH/HTTPS URLs), which can also fail but is only warned about, not propagated.

Source

Thrown at crates/but-gitlab/src/client.rs:308

        let mr: GitLabMergeRequest = response.json().await?;
        Ok(mr.into())
    }

    pub async fn get_merge_request(
        &self,
        project_id: GitLabProjectId,
        mr_iid: i64,
    ) -> Result<MergeRequest> {
        let url = format!(
            "{}/projects/{}/merge_requests/{}",
            self.base_url, project_id, mr_iid
        );

        let response = self.client.get(&url).send().await?;

        if !response.status().is_success() {
            bail!("Failed to get merge request: {}", response.status());
        }

        let mr: GitLabMergeRequest = response.json().await?;
        let mr = mr.into();
        match self.enrich_merge_request_source_project(mr).await {
            Ok(mr) => Ok(mr),
            Err(err) => {
                tracing::warn!(
                    error = ?err.source(),
                    project_id = %project_id,
                    mr_iid,
                    "Failed to enrich GitLab merge request source project"
                );
                Ok(err.into_inner())
            }
        }
    }

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Re-authenticate: run `but config forge auth` to refresh the GitLab token, then retry
  2. Verify the pair exists: open https://<host>/<project>/-/merge_requests/<iid> in a browser, or curl GET /api/v4/projects/<id>/merge_requests/<iid> with the same token
  3. Check the token's scopes (needs `api` or `read_api`) and that it belongs to an account with at least Reporter access to the project
  4. Confirm the configured GitLab host/base_url and that project_id matches that instance (not a numeric ID from another host)
  5. If the MR was deleted, invalidate the cached MR reference in your data so the UI stops requesting it

Example fix

// before
let mr = client.get_merge_request(project_id, mr_iid).await?; // aborts the whole flow on a 404

// after
let mr = match client.get_merge_request(project_id, mr_iid).await {
    Ok(mr) => Some(mr),
    Err(err) if err.to_string().contains("404") => {
        tracing::warn!(%mr_iid, "GitLab MR no longer exists, dropping from cache");
        None // treat as deleted instead of failing
    }
    Err(err) => return Err(err),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Confirm the project is visible with the same token before MR lookups
client.fetch_project(project_id.clone()).await?; // surfaces auth/project problems first
let mr = client.get_merge_request(project_id, mr_iid).await?;

Try / catch

match client.get_merge_request(project_id, mr_iid).await {
    Ok(mr) => Ok(Some(mr)),
    Err(err) if err.to_string().contains("404") => Ok(None), // MR deleted/invisible: not fatal
    Err(err) => Err(err.context("fetch GitLab merge request")),
}

Prevention

When it happens

Trigger: Calling get_merge_request(project_id, mr_iid) with an MR iid that does not exist (404), a project id the token cannot read (403 or 404), an expired/revoked personal access token (401), or a base_url pointing at the wrong GitLab instance where the project id does not resolve.

Common situations: Token expired between sessions; MR was merged and the source branch/project (fork) deleted, leaving a stale iid in local state; numeric project ID vs URL-encoded namespace/path confusion; self-hosted GitLab on an old version lacking the endpoint; user logged out or revoked the app/token.

Related errors


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