gitbutlerapp/gitbutler · error · anyhow::Error

Failed to create merge request: {status} - {error_text}

Error message

Failed to create merge request: {status} - {error_text}

What it means

The POST creating a GitLab merge request returned a non-2xx status; the message includes the status and GitLab's error body, which names the exact validation failure that caused the rejection.

Source

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

            None
        };

        let title = update_draft_state_in_title(params.title, params.draft);

        let body = CreateMergeRequestBody {
            title: &title,
            description: params.body,
            source_branch: params.source_branch,
            target_branch: params.target_branch,
            target_project_id,
        };

        let response = self.client.post(&url).json(&body).send().await?;

        if !response.status().is_success() {
            let status = response.status();
            let error_text = response.text().await.unwrap_or_default();
            bail!("Failed to create merge request: {status} - {error_text}");
        }

        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?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Read error_text: 'Another open merge request already exists for this source branch' - fetch and reuse the existing MR
  2. Verify the source branch is pushed and the target branch name exists exactly
  3. Check the token scope (api) and the project role (Developer or higher)
  4. Shorten title/description if the body reports validation limits

Example fix

// before
let mr = client.create_merge_request(project_id, &params).await?;

// after
let existing = client
    .list_merge_requests(project_id, State::Opened)
    .await?
    .into_iter()
    .find(|mr| mr.source_branch == params.source_branch);
let mr = match existing {
    Some(mr) => mr,
    None => client.create_merge_request(project_id, &params).await?,
};
Defensive patterns

Strategy: validation

Validate before calling

let existing = client
    .list_merge_requests(project_id, State::Opened)
    .await?
    .into_iter()
    .find(|mr| mr.source_branch == params.source_branch);
if existing.is_some() {
    anyhow::bail!("an open MR already exists for this source branch - reuse it");
}
// also: confirm target branch exists before creating
let branches = client.list_branches(project_id).await?;
if !branches.iter().any(|b| b.name == params.target_branch) {
    anyhow::bail!("target branch '{}' does not exist", params.target_branch);
}

Try / catch

if let Err(e) = client.create_merge_request(project_id, &params).await {
    if e.to_string().contains("already exists") {
        return client.list_merge_requests(project_id, State::Opened)
            .await?
            .into_iter()
            .find(|mr| mr.source_branch == params.source_branch)
            .ok_or(e); // fall back to the existing MR
    }
    return Err(e);
}

Prevention

When it happens

Trigger: An open MR already exists for the same source/target pair (DUPLICATE); the target branch does not exist (main vs master); the source branch was never pushed; source equals target branch; title or description exceeds limits; token lacks api scope or the role is below Developer.

Common situations: Re-running automation that already opened the MR; wrong default-branch names; forgetting to push the feature branch before creating the MR.

Related errors


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