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
- Re-authenticate: run `but config forge auth` to refresh the GitLab token, then retry
- 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
- 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
- Confirm the configured GitLab host/base_url and that project_id matches that instance (not a numeric ID from another host)
- 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
- Invalidate cached MR ids when the UI observes the MR as closed/merged/deleted
- Wrap status-code errors: the client bails with only the status string, so classify on '401'/'403'/'404' substrings until typed errors exist
- Refresh the GitLab token via `but config forge auth` whenever a 401 appears anywhere in the session
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
- Failed to get MR merge status: {}
- Failed to update merge request: {status} - {error_text}
- Failed to merge merge request: {}
- Failed to set merge request draft state: {status} - {error_t
- Failed to enable merge request auto-merge: {status} - {error
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/9726f20444f6c391.
Report an issue: GitHub.