{"record":{"id":"03f156bffdde1bf4","repo":"zed-industries/zed","slug":"graphql-error-result-errors-03f156","errorCode":null,"errorMessage":"GraphQL error: {result['errors']}","messagePattern":"GraphQL error: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"script/github-triage-queue-board.py","lineNumber":56,"sourceCode":"\ndef github_graphql(query, variables):\n    for attempt in range(MAX_RETRIES + 1):\n        response = requests.post(\n            f\"{GITHUB_API_URL}/graphql\",\n            headers=GITHUB_HEADERS,\n            json={\"query\": query, \"variables\": variables},\n            timeout=30,\n        )\n        if response.status_code in RETRYABLE_STATUS_CODES and attempt < MAX_RETRIES:\n            print(\n                f\"GitHub API returned {response.status_code}, retrying in {RETRY_DELAY_SECONDS}s (attempt {attempt + 1}/{MAX_RETRIES})...\"\n            )\n            time.sleep(RETRY_DELAY_SECONDS)\n            continue\n        response.raise_for_status()\n        result = response.json()\n        if \"errors\" in result:\n            raise RuntimeError(f\"GraphQL error: {result['errors']}\")\n        return result[\"data\"]\n    raise RuntimeError(\"github_graphql: retry loop exited without return\")\n\n\ndef github_rest_get(path):\n    for attempt in range(MAX_RETRIES + 1):\n        response = requests.get(\n            f\"{GITHUB_API_URL}/{path}\", headers=GITHUB_HEADERS, timeout=30\n        )\n        if response.status_code in RETRYABLE_STATUS_CODES and attempt < MAX_RETRIES:\n            print(\n                f\"GitHub API returned {response.status_code}, retrying in {RETRY_DELAY_SECONDS}s (attempt {attempt + 1}/{MAX_RETRIES})...\"\n            )\n            time.sleep(RETRY_DELAY_SECONDS)\n            continue\n        response.raise_for_status()\n        return response.json()\n    raise RuntimeError(\"github_rest_get: retry loop exited without return\")","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/script/github-triage-queue-board.py#L38-L74","documentation":"The triage queue board's github_graphql retries only HTTP statuses in RETRYABLE_STATUS_CODES (fixed sleep, 30s timeout); a 200 response carrying an \"errors\" array raises this RuntimeError with the raw errors. GraphQL application failures — the ones that come back with HTTP 200 — are therefore never retried.","triggerScenarios":"Board queries return 200 + errors: stale project/item node ids, missing read:project on the token, deprecated fields in the query after schema changes, or rate-limit text embedded in the errors body.","commonSituations":"Expired CI token; project recreated so fetch_project_id/item ids go stale; GitHub schema evolution breaking a fragment; rate pressure from overlapping scheduled runs.","solutions":["Read the errors array in the message to find the failing field/id/permission","Refresh the token and confirm project scopes","Re-run the query standalone with the same variables to reproduce","Make body-level rate-limit errors retryable like the HTTP 429 branch"],"exampleFix":"// before\nresult = response.json()\nif \"errors\" in result:\n    raise RuntimeError(f\"GraphQL error: {result['errors']}\")\n\n// after\nresult = response.json()\nif \"errors\" in result:\n    rate_limited = any(\"rate limit\" in str(e.get(\"message\", \"\")).lower() for e in result[\"errors\"])\n    if rate_limited and attempt < MAX_RETRIES:\n        time.sleep(RETRY_DELAY_SECONDS)\n        continue\n    raise RuntimeError(f\"GraphQL error: {result['errors']}\")","handlingStrategy":"retry","validationCode":"def graphql_request_is_well_formed(query: str, variables: dict) -> bool:\n    return bool(query.strip()) and isinstance(variables, dict)","typeGuard":"def is_graphql_error_body(payload: dict) -> bool:\n    return isinstance(payload, dict) and bool(payload.get(\"errors\"))","tryCatchPattern":"try:\n    data = github_graphql(query, variables)\nexcept RuntimeError as exc:\n    if \"rate limit\" in str(exc).lower():\n        time.sleep(RETRY_DELAY_SECONDS)\n        data = github_graphql(query, variables)\n    else:\n        raise","preventionTips":["Re-resolve ids each run instead of caching node ids","Keep the CI token's project scopes correct after rotations","Smoke-test queries after GitHub schema announcements","Separate retryable from permanent GraphQL errors in handling"],"tags":["github-api","graphql","python","rate-limit","api-auth"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}