Errors & Limits
Every error and rate limit on the feed socket and the accounts API.
Limits
| Where | Limit | Over it |
|---|---|---|
| Feed socket | 5 connections per user, shared with your app tabs | Too many connections |
| Feed socket | 15 client → server messages per second per socket | Dropped silently |
| Feed socket | Server pings every 30 s | Dropped after 60 s without a pong (Socket.IO answers for you) |
GET /api/watched-accounts | 30 per 10 s per user | 429 rate_limited, blocked 30 s |
POST account writes | 20 per 10 s per user | 429 rate_limited, blocked 45 s |
POST account writes | 3 running at once per user | 429 too_many_inflight |
POST /api/accounts/available | 25,000 handles per call | 400 too_many |
Every 429 carries a Retry-After header (seconds). A block lasts its full time even if you stop, so back off instead of retrying in a loop, and send account writes one after another rather than in parallel.
Feed socket
Connect errors arrive on Socket.IO's connect_error as err.message. Errors after user_connected arrive as an auth_error event.
{
// The JWT in `auth.token` is expired or isn't an access token. Log in again; don't retry with the same token.
INVALID_TOKEN: {
event: 'connect_error',
message: 'Invalid token',
},
// The account behind the JWT is disabled. Final.
ACCOUNT_DISABLED: {
event: 'connect_error',
message: 'Account disabled',
},
// The JWT doesn't map to a user.
UNKNOWN_USER: {
event: 'connect_error',
message: 'Unknown user',
},
// You already have 5 feed sockets open (app tabs count). Close one.
TOO_MANY_CONNECTIONS: {
event: 'connect_error' | 'auth_error',
message: 'Too many connections',
},
// The JWT sent in `user_connected` failed. Log in again.
INVALID_SESSION: {
event: 'auth_error',
message: 'Invalid session',
},
}Accounts API
Every accounts route answers errors with an HTTP status and a JSON body:
interface ErrorResponse {
ok: false; // `success: false` on GET /api/watched-accounts
code: string; // Short stable code, match on this
error: string; // Human-readable message
}Two errors come before auth and have no code: { "error": "unauthorized" } (401) and { "error": "origin not allowed" } (403).
{
// No JWT, or an invalid one, in `Authorization: Bearer` / `x-session-id`.
UNAUTHORIZED: {
status: 401,
error: 'unauthorized',
},
// A browser request from an origin other than j7tracker. Call the API from a server or script.
ORIGIN_NOT_ALLOWED: {
status: 403,
error: 'origin not allowed',
},
// Your account is disabled.
disabled: {
status: 403,
error: 'Account disabled',
},
// The JWT is valid but its user no longer exists.
no_user: {
status: 404,
error: 'User not found',
},
// Empty handle, or no handles in a batch body.
invalid_handle: {
status: 400,
error: 'Invalid account handle' | 'handle is required' | 'handles[] required',
},
// More than 25,000 handles in one body.
too_many: {
status: 400,
error: 'too many handles',
},
// The handle is already in your custom or available list.
already_added: {
status: 409,
error: '@<handle> is already in your custom accounts',
},
// Nobody tracks this handle, so it can't be added as an available account.
not_available: {
status: 404,
error: '@<handle> is not in the available accounts list',
},
// Fewer than 15 deploys and no purchased slots.
no_deploys: {
status: 403,
error: 'You need at least 15 deploys to add custom accounts. You have <n> deploys.',
},
// Every slot is used. Remove a custom account or buy more slots.
limit_reached: {
status: 403,
error:
| "You've reached your limit of <max> custom accounts (<n> deploys)."
| 'You can track 1 custom account (15+ deploys). Remove @<handle> first, or reach 50 deploys for 2 accounts.',
},
// The X account doesn't exist or is unavailable.
tracking_failed_invalid: {
status: 422,
error: 'Could not track @<handle> - account does not exist or is unavailable',
},
// J7's tracking capacity is full. Contact an admin.
tracking_failed_quota: {
status: 429,
error: 'Could not track @<handle> - API account limit reached. Contact admin to upgrade.',
},
// The tracking provider failed. Retry shortly.
tracking_failed_other: {
status: 502,
error: 'Could not track @<handle> - tracking provider error, try again shortly',
},
// The provider refused to stop tracking. Nothing was changed; retry.
untrack_failed: {
status: 502,
error: 'Could not remove @<handle> - tracking provider error, nothing was changed. Try again shortly.',
},
// Over a rate limit. Wait `Retry-After` seconds.
rate_limited: {
status: 429,
error: 'Too many requests, slow down',
},
// 3 account writes are already running for you. Wait for them to finish.
too_many_inflight: {
status: 429,
error: 'Too many account changes in progress, wait for them to finish',
},
// Server error on our end. Retry shortly.
internal_error: {
status: 500 | 503,
error: 'Could not save your account, try again shortly',
},
}