generated from yanyongyu/python-poetry-template
-
-
Notifications
You must be signed in to change notification settings - Fork 39
Open
Labels
Description
Hi,
On graphql api, when there is a error due to rate limit, the api return
{"errors":[{"type":"RATE_LIMIT","code":"graphql_rate_limit","message":"API rate limit already exceeded for user ID xxxxx."}]}And on graphql client, try to find the string the error.type = "RATE_LIMITED"
def parse_graphql_response(
self, response: "Response[GraphQLResponse]"
) -> dict[str, Any]:
response_data = response.parsed_data
if response_data.errors:
# check rate limit exceeded
# https://docs.github.com/en/graphql/overview/rate-limits-and-node-limits-for-the-graphql-api#exceeding-the-rate-limit
# x-ratelimit-remaining may not be 0, ignore it
# https://github.com/octokit/plugin-throttling.js/pull/636
if any(error.type == "RATE_LIMIT" for error in response_data.errors):
raise PrimaryRateLimitExceeded(
response, self._github._extract_retry_after(response)
)
raise GraphQLFailed(response_data)
return cast(dict[str, Any], response_data.data)
i am not sure if there have been more changes on rate limit, in theory retry-after header can be present
https://docs.github.com/en/graphql/overview/rate-limits-and-query-limits-for-the-graphql-api
But I've tried to find information about the different errors that GraphQL can return, and I haven't been able to find them.
Request/response migration query
Request Headers: {'host': 'api.github.com', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'GitHubKit/Python', 'accept': 'application/vnd.github+json', 'content-length': '429', 'content-type': 'application/json', 'authorization': 'token xxxx'}
Request Body: b'{"query":"\\nquery($id: ID!) { \\n node(id: $id) {\\n ... on Migration {\\n id,\\n sourceUrl,\\n migrationLogUrl,\\n migrationSource {\\n name\\n },\\n state,\\n warningsCount,\\n failureReason,\\n repositoryName\\n }\\n } \\n}\\n","variables":{"id":"yyyy"}}'
Response Headers: {'date': 'Thu, 08 Jan 2026 16:49:49 GMT', 'content-type': 'application/json; charset=utf-8', 'x-oauth-scopes': 'admin:org, repo, workflow', 'x-accepted-oauth-scopes': 'repo', 'x-github-media-type': 'github.v4; format=json', 'x-ratelimit-limit': '5000', 'x-ratelimit-remaining': '0', 'x-ratelimit-reset': '1767892233', 'x-ratelimit-used': '5018', 'x-ratelimit-resource': 'graphql', 'access-control-expose-headers': 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset', 'access-control-allow-origin': '*', 'strict-transport-security': 'max-age=31536000; includeSubdomains; preload', 'x-frame-options': 'deny', 'x-content-type-options': 'nosniff', 'x-xss-protection': '0', 'referrer-policy': 'origin-when-cross-origin, strict-origin-when-cross-origin', 'content-security-policy': "default-src 'none'", 'vary': 'Accept-Encoding, Accept, X-Requested-With', 'content-encoding': 'gzip', 'transfer-encoding': 'chunked', 'server': 'github.com', 'x-github-request-id': '4C25:1F1B3F:2B04832:26C1653:695FE02C'}
Response Body: {"errors":[{"type":"RATE_LIMIT","code":"graphql_rate_limit","message":"API rate limit already exceeded for user ID zzzzz."}]}
Request/response list repo query
Request Headers: {'host': 'api.github.com', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'GitHubKit/Python', 'accept': 'application/vnd.github+json', 'content-length': '163', 'content-type': 'application/json', 'authorization': 'token xxxx'}
Request Body: b'{"query":"\\nquery ($owner: String!, $repo: String!) {\\n repository(owner: $owner, name: $repo) {\\n name\\n }\\n}\\n","variables":{"owner":"owner","repo":"repo"}}'
Response Headers: {'date': 'Thu, 08 Jan 2026 17:21:18 GMT', 'content-type': 'application/json; charset=utf-8', 'x-oauth-scopes': 'admin:org, repo, workflow', 'x-accepted-oauth-scopes': 'repo', 'x-github-media-type': 'github.v4; format=json', 'x-ratelimit-limit': '5000', 'x-ratelimit-remaining': '0', 'x-ratelimit-reset': '1767896168', 'x-ratelimit-used': '5002', 'x-ratelimit-resource': 'graphql', 'access-control-expose-headers': 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset', 'access-control-allow-origin': '*', 'strict-transport-security': 'max-age=31536000; includeSubdomains; preload', 'x-frame-options': 'deny', 'x-content-type-options': 'nosniff', 'x-xss-protection': '0', 'referrer-policy': 'origin-when-cross-origin, strict-origin-when-cross-origin', 'content-security-policy': "default-src 'none'", 'vary': 'Accept-Encoding, Accept, X-Requested-With', 'content-encoding': 'gzip', 'transfer-encoding': 'chunked', 'server': 'github.com', 'x-github-request-id': '6042:18034E:2DBF8B5:29287C7:695FE78E'}
Response Body: {"errors":[{"type":"RATE_LIMIT","code":"graphql_rate_limit","message":"API rate limit already exceeded for user ID xxxx."}]}
After change error.type to "RATE_LIMIT", It returns the expected exception because it cannot find the headers.
55 if response_data.errors:
56 # check rate limit exceeded
57 # https://docs.github.com/en/graphql/overview/rate-limits-and-node-limits-for-the-graphql-api#exceeding-the-rate-limit
58 # x-ratelimit-remaining may not be 0, ignore it
59 # https://github.com/octokit/plugin-throttling.js/pull/636
60 if any(error.type == "RATE_LIMIT" for error in response_data.errors):
---> 61 raise PrimaryRateLimitExceeded(
62 response, self._github._extract_retry_after(response)
63 )
64 raise GraphQLFailed(response_data)
65 return cast(dict[str, Any], response_data.data)
PrimaryRateLimitExceeded: (Response(200 OK, data_model=<class 'githubkit.graphql.models.GraphQLResponse'>), datetime.timedelta(seconds=3289, microseconds=326017))
yanyongyu