gitbutlerapp/gitbutler · error · anyhow::Error

GitHub GraphQL disablePullRequestAutoMerge returned an empty

Error message

GitHub GraphQL disablePullRequestAutoMerge returned an empty pull request id

What it means

The disablePullRequestAutoMerge GraphQL mutation returned but pullRequest.id was empty. As with enable, GitHub nulls the field when the mutation is refused or inapplicable - most commonly because auto-merge is not currently enabled on that PR, so there is nothing to disable.

Source

Thrown at crates/but-github/src/client.rs:1180

        }

        #[derive(Deserialize)]
        struct MutationData {
            #[serde(rename = "disablePullRequestAutoMerge")]
            disable_pull_request_auto_merge: MutationPayload,
        }

        let data: MutationData = self
            .graphql_query(GQL_DISABLE_PR_AUTO_MERGE, &Variables { pull_request_id })
            .await?;

        if data
            .disable_pull_request_auto_merge
            .pull_request
            .id
            .is_empty()
        {
            bail!("GitHub GraphQL disablePullRequestAutoMerge returned an empty pull request id");
        }

        Ok(())
    }

    async fn get_pull_request_node_id(
        &self,
        owner: &str,
        repo: &str,
        pr_number: i64,
    ) -> Result<PullRequestNodeId> {
        #[derive(Serialize)]
        struct Variables<'a> {
            owner: &'a str,
            repo: &'a str,
            number: i64,
        }

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Make disable idempotent: fetch the PR first and only call when auto_merge_enabled is true (but-github's PullRequest type already exposes this flag)
  2. Refresh PR state immediately before disabling
  3. If GitHub still shows auto-merge but the call fails, verify the token's permissions

Example fix

// before
client.disable_auto_merge_pull_request(&pr_id).await?;

// after
let pr = client.get_pull_request(owner, repo, number).await?;
if pr.auto_merge_enabled {
    client.disable_auto_merge_pull_request(&pr_id).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

let pr = client.get_pull_request(owner, repo, number).await?;
if !pr.auto_merge_enabled {
    // nothing to disable - auto-merge already off
    return Ok(());
}

Try / catch

if let Err(e) = client.disable_auto_merge_pull_request(&pr_id).await {
    if e.to_string().contains("empty pull request id") {
        // treat as already-disabled: verify via a fresh GET instead of retrying
        return Ok(());
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling disable on a PR whose auto-merge was already cancelled (e.g. checks failed and GitHub dropped it), on a closed or merged PR, or with a token that lacks write permission.

Common situations: Client/UI state out of sync with GitHub's auto-merge state; double-running a disable action; acting on stale PR data.

Related errors


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