gitbutlerapp/gitbutler · error · anyhow::Error

GitHub GraphQL pull request #{pr_number} in {owner}/{repo} r

Error message

GitHub GraphQL pull request #{pr_number} in {owner}/{repo} returned an empty node id

What it means

The pullRequest object resolved but its node id came back as an empty string. Node ids are what subsequent GraphQL mutations (auto-merge enable/disable) require, so the client refuses instead of handing on a useless id. This shape is not something github.com normally returns.

Source

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

                GQL_GET_PR_NODE_ID,
                &Variables {
                    owner,
                    repo,
                    number: pr_number,
                },
            )
            .await?;

        let Some(repository) = data.repository else {
            bail!("GitHub GraphQL repository not found for {owner}/{repo}");
        };

        let Some(pull_request) = repository.pull_request else {
            bail!("GitHub GraphQL pull request #{pr_number} not found for {owner}/{repo}",);
        };

        if pull_request.id.is_empty() {
            bail!(
                "GitHub GraphQL pull request #{pr_number} in {owner}/{repo} returned an empty node id",
            );
        }

        Ok(PullRequestNodeId::from_string(pull_request.id))
    }

    async fn graphql_query<T, V>(&self, query: &str, variables: &V) -> Result<T>
    where
        T: for<'de> Deserialize<'de>,
        V: Serialize,
    {
        #[derive(Serialize)]
        struct GraphQlRequest<'a, V> {
            query: &'a str,
            variables: &'a V,
        }

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Retry the lookup once - transient response anomalies happen
  2. Verify the configured base URL reaches a real GitHub GraphQL endpoint
  3. If persistent, capture the raw response body and report it upstream
Defensive patterns

Strategy: retry

Try / catch

let node_id = match client.get_pull_request_node_id(owner, repo, n).await {
    Err(e) if e.to_string().contains("empty node id") => {
        tokio::time::sleep(Duration::from_secs(2)).await;
        client.get_pull_request_node_id(owner, repo, n).await? // one retry
    }
    other => other?,
};

Prevention

When it happens

Trigger: A proxy or gateway rewriting or truncating the GraphQL response; exotic GitHub Enterprise Server versions; a transient GitHub-side serialization anomaly.

Common situations: Rare against github.com; more likely with custom base URLs, misconfigured GHE instances, or API gateways that inspect and rewrite JSON.

Related errors


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