{"record":{"id":"fe801c9f7dc47a95","repo":"gitbutlerapp/gitbutler","slug":"github-graphql-returned-errors-messages","errorCode":null,"errorMessage":"GitHub GraphQL returned errors: {messages}","messagePattern":"GitHub GraphQL returned errors: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-github/src/client.rs","lineNumber":1300,"sourceCode":"    struct GraphQlError {\n        message: String,\n    }\n\n    #[derive(Deserialize)]\n    struct GraphQlResponse {\n        data: Option<serde_json::Value>,\n        errors: Option<Vec<GraphQlError>>,\n    }\n\n    let payload: GraphQlResponse = serde_json::from_slice(body)?;\n\n    if let Some(errors) = payload.errors {\n        let messages = errors\n            .into_iter()\n            .map(|error| error.message)\n            .collect::<Vec<_>>()\n            .join(\"; \");\n        bail!(\"GitHub GraphQL returned errors: {messages}\");\n    }\n\n    let Some(data) = payload.data else {\n        bail!(\"GitHub GraphQL response did not include data\");\n    };\n\n    Ok(serde_json::from_value(data)?)\n}\n\npub struct PullRequestNodeId {\n    id: String,\n}\n\nimpl PullRequestNodeId {\n    pub fn from_string(value: String) -> Self {\n        PullRequestNodeId { id: value }\n    }\n}","sourceCodeStart":1282,"sourceCodeEnd":1318,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-github/src/client.rs#L1282-L1318","documentation":"The GraphQL response contained a top-level `errors` array; but-github joins the error messages with '; ' and fails. This is how every GraphQL-level refusal surfaces: insufficient scopes, invalid variables, failed preconditions (e.g. NOT_READY_FOR_AUTO_MERGE), or rate-limit messages.","triggerScenarios":"Mutating a PR that fails a precondition; a token missing the required OAuth scopes; querying fields the token cannot see; variable type mismatches in the query.","commonSituations":"Enabling auto-merge before required checks pass; read-scoped tokens used for writes; GitHub API version drift on GitHub Enterprise Server.","solutions":["Read the joined message(s) - they carry the exact GraphQL error type","Fix the named precondition (PR state, repo settings, scopes) and retry","If scope-related, re-authenticate so the token gains the needed scopes"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.graphql_query(query, &vars).await {\n    Err(e) if e.to_string().starts_with(\"GitHub GraphQL returned errors:\") => {\n        let msg = e.to_string();\n        if msg.contains(\"rate limit\") { backoff_and_retry().await } else { Err(e) }\n    }\n    other => other?,\n}","preventionTips":["Read the joined messages - they name the exact GraphQL error type","Verify PR preconditions before mutations","Ensure the token carries the scopes the query or mutation needs"],"tags":["github","graphql","api-errors","permissions"],"backgroundTag":"graphql-api-errors","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}