Grok API errors fall into four broad categories: credentials and permissions, paths and model names, rate limits and quotas, and network timeouts. The correct order is to check the HTTP status code and error type first, then the request ID, and only then consider changing prompts or model parameters. Reverse that order and you will treat configuration problems as model problems.
This article breaks down 401, 404, 429, and timeouts, with causes, diagnostic steps, and reusable backoff code. Models and prices are subject to model pricing on this site.
Note: xAI and Grok are trademarks of their respective owners. This article is for technical reference only. Error types and interface behavior may change between versions; this article reflects common cases as of October 2026 and defers to xAI's official documentation.
1. Read the status code first, not the prompt
| Status | Common meaning | Retry? |
|---|---|---|
| 400 | Problem with parameters, format, or context length | Fix the request, then retry |
| 401 | Key missing, wrong, expired, or mismatched with the address | Do not retry; fix credentials first |
| 403 | Account or key lacks permission, or regional or terms restrictions apply | Do not retry; check permissions and account status |
| 404 | Wrong path or nonexistent model name | Do not retry; check the address and model name |
| 429 | Request rate, concurrency, or token limit exceeded | Retry with backoff |
| 500 | Internal error in the upstream service | Retry with backoff |
| 502 or 503 | Gateway or upstream temporarily unavailable | Retry with backoff |
| 504 | Gateway timed out waiting for upstream | Reduce load and retry |
Keep the request ID from the response. When you ask a provider for help, one request ID is more useful than ten screenshots. Log at least the timestamp, status code, error type, model name, and request ID. Do not log full keys or sensitive content.
2. 401: check the request header, then the key
A 401 means authentication failed. It has nothing to do with balance or model capability. Check in this order:
- Is the auth header written as
Authorization: Bearer <key>? The OpenAI-compatible Grok endpoint does not usex-api-key. - Are there spaces, newlines, or extra quotation marks around the key? Copying from a chat window is the most common cause.
- Do the key and base URL come from the same provider? An official key against a gateway address, or a gateway key against the official address, will both fail.
- Has the key been revoked or expired, or does its project lack call permission?
- Did the environment variable actually load? Print only the first few characters to confirm; never write the full value to logs.
- Does the base URL point to the correct environment, and is the path
/v1/chat/completions?
export GROK_API_KEY="sk-your-key"
curl "https://ai.zhongshangqihang.com/v1/chat/completions" \
-H "Authorization: Bearer $GROK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-4",
"messages": [{"role": "user", "content": "Reply with OK only"}],
"max_tokens": 16
}'
A 200 response means the key, address, and model name all work. If you still get a 401, test the same key against a different entry point. That distinguishes a problem with the key itself from a gateway configuration or network-layer problem.
3. 404: check both the path and the model name
A 404 usually is not a key problem. It means "the thing you requested does not exist." There are four common causes:
- The base URL already contains
/v1, and the code appends it again, producing/v1/v1/chat/completions. - The endpoint is written as
/completionsor/responses, while the current entry point only provides Chat Completions. - The model name is misspelled, or the account or group does not have that model enabled.
- The base URL has a trailing slash, producing a double slash or a malformed path after joining.
Diagnostic order: first request the standard path from the official documentation with curl, then copy the model name from the console or model pricing. Do not write model names from memory, and do not carry over model names from another platform.
4. 429: rate limiting is not a low balance
A 429 means the request exceeded a rate or quota limit. Common triggers:
- Requests per minute or tokens per minute exceeded.
- A sudden concurrency spike that consumes the quota in a short period.
- Several services sharing one key and competing for the same quota.
- Retries without backoff, sending more requests as failures increase, creating a retry storm.
- Long outputs consuming more output tokens and leaving less room for concurrent requests.
| Symptom | Likely cause | Handling |
|---|---|---|
| Concentrated 429s during peak hours | Traffic burst | Queue and smooth the send rate |
| 429s with one key across several services | Shared quota | Split keys by project |
| Worse after adding retries | Retries without backoff | Exponential backoff with jitter |
| Long requests hit 429 first | High output-token usage | Lower max_tokens or concurrency |
Check the retry-after value in the response, if present, before deciding how long to wait. Use the SDK's error types rather than string-matching error messages:
import random
import time
from openai import OpenAI, APIStatusError, RateLimitError
client = OpenAI(
api_key="sk-your-key",
base_url="https://ai.zhongshangqihang.com/v1",
)
def ask(prompt: str, retries: int = 4) -> str:
for attempt in range(retries):
try:
resp = client.chat.completions.create(
model="grok-4",
messages=[{"role": "user", "content": prompt}],
max_tokens=1024,
)
return resp.choices[0].message.content
except RateLimitError:
wait = min(2 ** attempt, 20) + random.random()
print(f"429, retry {attempt + 1}, waiting {wait:.1f}s")
time.sleep(wait)
except APIStatusError as exc:
if exc.status_code >= 500:
wait = min(2 ** attempt, 20) + random.random()
print(f"{exc.status_code}, retrying in {wait:.1f}s")
time.sleep(wait)
continue
raise
raise RuntimeError("Retry limit reached")
Retries are appropriate only for transient errors. For operations that have already produced side effects, check with an idempotency key or a status query before deciding whether to resend.
5. Timeouts and connection errors
Timeout handling should distinguish connect timeouts from read timeouts. A connect timeout usually points to a network, DNS, or proxy problem. A read timeout may mean the model is taking a long time to generate, a streaming response was interrupted, or the proxy's idle timeout is too short.
Diagnostic order:
- Use curl to record
time_namelookup,time_connect,time_appconnect, andtime_starttransfer, and see which stage consumes the time. - Confirm whether the proxy has an overly short connect or idle timeout.
- Use streaming for long outputs so you read while the model generates, instead of waiting for the complete response.
- Set separate connect and read timeouts on the client. Do not rely on one very large overall timeout.
- After a timeout, determine whether the request was already executed before retrying, to avoid duplicate charges or duplicate writes.
export GROK_API_KEY="sk-your-key"
curl -o /dev/null -s \
-w "code=%{http_code} dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n" \
--max-time 120 \
"https://ai.zhongshangqihang.com/v1/chat/completions" \
-H "Authorization: Bearer $GROK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"grok-4","messages":[{"role":"user","content":"Reply with OK only"}],"max_tokens":8}'
If DNS and connection are fast but the first byte is slow, the problem is likely generation or the upstream service. If the connection stage itself times out, check egress and the proxy first; do not change business code.
6. A troubleshooting order
- Record the status code, error type, request ID, model name, and time of occurrence.
- For 401 and 403, check credentials, account status, and permissions. For 404, check the path and model name.
- For 400, check parameters, context length, image format, and request body size.
- For 429, check quota, concurrency, shared keys, and retry storms.
- For timeouts, examine DNS, connection, TLS, first byte, and total time layer by layer.
- For 5xx, retry with backoff first. If it persists, contact the provider with the request ID.
- After every incident, add monitoring and alerts. Do not wait for user reports to discover failures.
FAQ
What is the difference between a 429 and a low balance?
A 429 means the request exceeded a rate or quota limit, and topping up may not fix it. A low balance usually returns a quota or billing-related error. Check the error type and the bill before deciding whether to wait, reduce concurrency, or top up.
Why do 429s increase after I add retries?
You may be retrying without backoff, running too much concurrency, or sharing one key across services. Aggressive retries at fixed intervals turn a small rate limit into a retry storm. Use exponential backoff with jitter and set a maximum retry count.
The model exists, so why do I still get a 404?
Check whether the base URL appends /v1 twice, then confirm the endpoint is /chat/completions. If the path is correct, the account or group may not have the model enabled, or the model name's capitalization or version suffix may not match.
Can I resend immediately after a timeout?
First determine whether the request was already executed. Read-only queries can usually be retried. Operations that write data, charge money, or produce external side effects should use an idempotency key or a status query first to avoid duplicate execution.
How can I tell a gateway error from an upstream error?
Check the error type and request ID first, then send the same request to both the gateway entry point and the official entry point. That quickly separates key, network, gateway configuration, and upstream service problems.
Next steps
Create a test key at the ZSQH AI Gateway, rehearse 401, 404, 429, and timeout scenarios once each, and then connect production monitoring. Model availability and prices are subject to model pricing.
Related reading:
