{"record":{"id":"efe57cef08dd6558","repo":"gitbutlerapp/gitbutler","slug":"github-graphql-markpullrequestreadyforreview-returned-an","errorCode":null,"errorMessage":"GitHub GraphQL markPullRequestReadyForReview returned an empty pull request id","messagePattern":"GitHub GraphQL markPullRequestReadyForReview returned an empty pull request id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":1555,"sourceCode":"            pull_request: GraphQlPullRequest,\n        }\n\n        #[derive(Deserialize)]\n        struct GraphQlPullRequest {\n            id: String,\n        }\n\n        let data: MutationData = self\n            .graphql_query(GQL_SET_PR_READY_FOR_REVIEW, &Variables { pull_request_id })\n            .await?;\n\n        if data\n            .mark_pull_request_ready_for_review\n            .pull_request\n            .id\n            .is_empty()\n        {\n            bail!(\"GitHub GraphQL markPullRequestReadyForReview returned an empty pull request id\");\n        }\n\n        Ok(())\n    }\n\n    async fn set_pull_request_to_draft(&self, pull_request_id: &PullRequestNodeId) -> Result<()> {\n        #[derive(Serialize)]\n        #[serde(rename_all = \"camelCase\")]\n        struct Variables<'a> {\n            pull_request_id: &'a PullRequestNodeId,\n        }\n\n        #[derive(Deserialize)]\n        struct MutationData {\n            #[serde(rename = \"convertPullRequestToDraft\")]\n            convert_pull_request_to_draft: MutationPayload,\n        }\n","sourceCodeStart":1537,"sourceCodeEnd":1573,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-github/src/client.rs#L1537-L1573","documentation":"The markPullRequestReadyForReview GraphQL mutation succeeded at the HTTP level and returned data, but the pull_request.id in the response was an empty string. The library treats a missing node id as an unusable/protocol-violating response and bails.","triggerScenarios":"Calling mark_pull_request_ready_for_review when GitHub's response omits or empties the returned PR node id — typically because the mutation targeted a PR in a state where the mutation no-ops or the payload shape changed (API schema drift).","commonSituations":"PR is already marked ready for review (mutation returns but id may be empty in edge payloads); PR is actually a draft of a fork where permissions differ; GitHub API schema changes between versions.","solutions":["Check the PR's current state first and skip the mutation if it is already ready for review","Verify the mutation response JSON manually (e.g. with gh api graphql) to confirm GitHub is returning the id","Retry once; if it persists, check GitHub API status/changelog for GraphQL schema changes","Ensure the token can act on this PR (permissions on the fork/repo)"],"exampleFix":"// before\nclient.mark_pull_request_ready_for_review(&params).await?;\n// after\nif !is_draft(pr) {\n    return Ok(()); // already ready, skip mutation\n}\nclient.mark_pull_request_ready_for_review(&params).await?;","handlingStrategy":"validation","validationCode":"// skip the mutation when the PR is not a draft\nif !pr.is_draft { return Ok(()); }","typeGuard":null,"tryCatchPattern":"// treat empty-id as possibly benign (already ready) and refetch state\nmatch client.mark_pull_request_ready_for_review(&params).await {\n    Err(e) if e.to_string().contains(\"empty pull request id\") => {\n        let pr = client.get_pull_request(owner, repo, pr_number).await?;\n        if !pr.is_draft { Ok(()) } else { Err(e) }\n    }\n    other => other,\n}","preventionTips":["Check PR draft state before calling ready-for-review","Keep the crate updated with GitHub GraphQL schema changes","Test the raw mutation with gh api graphql when debugging","Retry idempotent state mutations once before failing"],"tags":["github","graphql","pull-request","response-validation"],"backgroundTag":"empty-required-field","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}