zed-industries/zed · error · RuntimeError
GraphQL error: {result['errors']}
Error message
GraphQL error: {result['errors']} What it means
The guild board's github_graphql helper retries only HTTP statuses in RETRYABLE_STATUS_CODES (with a fixed sleep and a 30s timeout per request); a 200 response whose body contains an "errors" array raises this RuntimeError with the raw errors. Application-level GraphQL failures therefore bypass the retry loop entirely.
Source
Thrown at script/github-guild-board.py:112
"A tell-tale ping beneath the board.",
]
def github_graphql(query, variables):
for attempt in range(MAX_RETRIES + 1):
response = requests.post(
f"{GITHUB_API_URL}/graphql",
headers=GITHUB_HEADERS,
json={"query": query, "variables": variables},
timeout=30,
)
if response.status_code in RETRYABLE_STATUS_CODES and attempt < MAX_RETRIES:
time.sleep(RETRY_DELAY_SECONDS)
continue
response.raise_for_status()
result = response.json()
if "errors" in result:
raise RuntimeError(f"GraphQL error: {result['errors']}")
return result["data"]
raise RuntimeError("github_graphql: retry loop exited without return")
def github_rest_request(method, path, body=None):
url = f"{GITHUB_API_URL}/{path}"
for attempt in range(MAX_RETRIES + 1):
response = requests.request(
method, url, headers=GITHUB_HEADERS, json=body, timeout=30
)
if response.status_code in RETRYABLE_STATUS_CODES and attempt < MAX_RETRIES:
time.sleep(RETRY_DELAY_SECONDS)
continue
response.raise_for_status()
if response.status_code == 204 or not response.content:
return None
return response.json()
raise RuntimeError("github_rest_request: retry loop exited without return")View on GitHub (pinned to bc538def45)
Solutions
- Inspect result['errors'] in the message: type and message identify the failing field, id, or permission
- Verify token validity and scopes (read:project, plus write for the mutations)
- Refresh any hardcoded node ids or project numbers whose objects were recreated
- Treat body-level rate-limit errors as retryable in the loop, like the HTTP 429 branch
Example fix
// before
result = response.json()
if "errors" in result:
raise RuntimeError(f"GraphQL error: {result['errors']}")
// after
result = response.json()
if "errors" in result:
transient = any("rate limit" in str(e.get("message", "")).lower() for e in result["errors"])
if transient and attempt < MAX_RETRIES:
time.sleep(RETRY_DELAY_SECONDS)
continue
raise RuntimeError(f"GraphQL error: {result['errors']}") Defensive patterns
Strategy: retry
Validate before calling
def graphql_request_is_well_formed(query: str, variables: dict) -> bool:
return bool(query.strip()) and isinstance(variables, dict) Type guard
def is_graphql_error_body(payload: dict) -> bool:
return isinstance(payload, dict) and bool(payload.get("errors")) Try / catch
try:
data = github_graphql(query, variables)
except RuntimeError as exc:
if "rate limit" in str(exc).lower():
time.sleep(RETRY_DELAY_SECONDS)
data = github_graphql(query, variables)
else:
raise Prevention
- Resolve node ids dynamically instead of persisting them
- Verify token scopes before scheduled runs
- Watch GitHub GraphQL changelogs for ProjectV2 field deprecations
- Retry only classified transient errors; permanent ones should fail loudly
When it happens
Trigger: Board queries or the ProjectV2 mutations return 200 + errors: stale project/item node ids, missing project scopes on the token, deprecated GraphQL fields after schema churn, or rate-limit messages placed in the body.
Common situations: Token rotated without project scopes; projects/issues recreated invalidating node ids; GitHub schema changes deprecating a field used in the query's fragments; sustained CI load triggering secondary rate limits.
Related errors
- GraphQL errors: {json.dumps(data['errors'])[:300]}
- GraphQL error: {result['errors']}
- GraphQL error: {result['errors']}
- GraphQL failed after {retries} retries: {last_err}
- GraphQL errors: {data['errors']}
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/81aa94b8f11f5deb.
Report an issue: GitHub.