affaan-m/ECC · error · Exception
Rate limited. Resets at {reset}
Error message
Rate limited. Resets at {reset} What it means
A generic Exception raised by X (Twitter) API posting code when the response status is 429 Too Many Requests. The reset timestamp is read from the x-rate-limit-reset response header. This indicates the app has exhausted its allotted requests for the current rate-limit window.
Source
Thrown at skills/x-api/SKILL.md:204
```python
import time
remaining = int(resp.headers.get("x-rate-limit-remaining", 0))
if remaining < 5:
reset = int(resp.headers.get("x-rate-limit-reset", 0))
wait = max(0, reset - int(time.time()))
print(f"Rate limit approaching. Resets in {wait}s")
```
## Error Handling
```python
resp = oauth.post("https://api.x.com/2/tweets", json={"text": content})
if resp.status_code == 201:
return resp.json()["data"]["id"]
elif resp.status_code == 429:
reset = int(resp.headers["x-rate-limit-reset"])
raise Exception(f"Rate limited. Resets at {reset}")
elif resp.status_code == 403:
raise Exception(f"Forbidden: {resp.json().get('detail', 'check permissions')}")
else:
raise Exception(f"X API error {resp.status_code}: {resp.text}")
```
## Security
- **Never hardcode tokens.** Use environment variables or `.env` files.
- **Never commit `.env` files.** Add to `.gitignore`.
- **Rotate tokens** if exposed. Regenerate at developer.x.com.
- **Use read-only tokens** when write access is not needed.
- **Store OAuth secrets securely** — not in source code or logs.
## Integration with Content Engine
Use `brand-voice` plus `content-engine` to generate platform-native content, then post via X API:
1. Pull recent original posts when voice matching mattersView on GitHub (pinned to 01e15490f0)
Solutions
- Read x-ratelimit-remaining before each post and sleep until x-rate-limit-reset when it hits zero.
- Implement exponential backoff with jitter and respect the Retry-After header if present.
- Queue posts and drain at a rate safely below the limit (e.g. via a token bucket or a queue worker).
- Split load across multiple app credentials only if permitted by the developer agreement.
- Use the v2 endpoint's batch capabilities where available to reduce request count.
Example fix
# before
elif resp.status_code == 429:
reset = int(resp.headers["x-rate-limit-reset"])
raise Exception(f"Rate limited. Resets at {reset}")
# after: pause instead of crashing the job
import time
reset = int(resp.headers.get("x-rate-limit-reset", time.time() + 900))
wait = max(1, reset - int(time.time()))
time.sleep(wait)
return retry_post(content) Defensive patterns
Strategy: retry
Validate before calling
def can_post_now(oauth) -> bool:
# lightweight GET to read rate-limit headers without consuming post quota
return True # actual check reads headers after each post
# before posting, sleep if a prior response said quota was low
if next_reset_at and time.time() < next_reset_at:
time.sleep(next_reset_at - time.time()) Type guard
null
Try / catch
try:
post_tweet(content)
except RateLimitError as e:
wait = max(1, e.reset_at - int(time.time()))
time.sleep(wait)
post_tweet(content) # one retry after reset Prevention
- Track x-rate-limit-remaining after each call and pause at zero.
- Queue posts and drain below the limit.
- Use exponential backoff with jitter for retries.
When it happens
Trigger: Calling oauth.post('https://api.x.com/2/tweets', ...) more times than the endpoint allows within the 15-minute window, or hitting an app-level daily limit. The header x-rate-limit-reset is a Unix timestamp of when the window resets.
Common situations: Bulk posting in a tight loop without checking remaining quota; multiple processes sharing one app token; a retry storm after transient errors; running a scheduled job more frequently than the tier allows.
Related errors
- Forbidden: {resp.json().get('detail', 'check permissions')}
- X API error {resp.status_code}: {resp.text}
- Missing value for --target
- Unknown argument: ${arg}
- Catalog show requires an install component ID
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/55bb60dfce2e5469.
Report an issue: GitHub.