All error responses follow a consistent format:
{
"error": {
"code": "error_code",
"message": "Human-readable description",
"request_id": "req_xxx"
}
}
HTTP Status Codes
400 Bad Request
Invalid request body or missing required fields.
{
"error": {
"code": "bad_request",
"message": "Missing or invalid \"namespace\" field",
"request_id": "req_a1b2c3d4..."
}
}
Common causes:
- Invalid JSON body
- Missing required field (
namespace,identifier,limit,window) - Invalid field type (e.g., string instead of number for
limit) - Negative or zero values for
limitorwindow
Fix: Check your request body matches the expected format:
{
"namespace": "api",
"identifier": "user_123",
"limit": 100,
"window": 60000
}
401 Unauthorized
Missing or invalid API key.
{
"error": {
"code": "unauthorized",
"message": "Invalid API key format",
"request_id": "req_a1b2c3d4..."
}
}
Common causes:
- Missing
Authorizationheader - Invalid key format (doesn't match
ts_limiter_{mode}_{32chars}) - Revoked API key
- Using wrong product key (e.g.,
ts_cache_on TinyLimiter)
Fix: Verify your API key:
# Correct
Authorization: Bearer ts_limiter_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
# Wrong product
Authorization: Bearer ts_cache_live_xxx # ❌ Wrong prefix for TinyLimiter
402 Payment Required
Live mode key requires active subscription.
{
"error": {
"code": "payment_required",
"message": "Live mode API keys require an active subscription. Subscribe at dashboard.tinyscale.io or use a test mode key.",
"request_id": "req_a1b2c3d4..."
}
}
Common causes:
- Using live key without subscription
- Subscription canceled or expired
- Payment method declined
Fix:
- Subscribe at dashboard.tinyscale.io
- Or switch to a test mode key (
ts_limiter_test_)
429 Too Many Requests
Rate limit exceeded on the management API itself.
{
"error": {
"code": "rate_limited",
"message": "Too many requests",
"request_id": "req_a1b2c3d4..."
}
}
:::note
This is for TinyScale's own API rate limits (not your rate limits). The /v1/check endpoint returns allowed: false in the response body, not a 429 status.
:::
500 Internal Server Error
Server-side error.
{
"error": {
"code": "internal_error",
"message": "Internal server error",
"request_id": "req_a1b2c3d4..."
}
}
What to do:
- Retry the request after a brief delay
- If persistent, check our status page
- Contact support with the
request_id
Error Handling Best Practices
async function checkRateLimit(userId) {
try {
const response = await fetch('https://limiter.tinyscale.io/v1/check', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TINYSCALE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
namespace: 'api',
identifier: userId,
limit: 100,
window: 60000,
}),
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
console.error('Invalid API key:', error.error.message);
// Fall through - allow request (fail open)
return true;
case 402:
console.error('Subscription required:', error.error.message);
// Fall through - allow request (fail open)
return true;
case 500:
console.error('TinyScale error:', error.error.request_id);
// Fail open - don't block users due to our outage
return true;
default:
console.error('Unexpected error:', error);
return true;
}
}
const { data } = await response.json();
return data.allowed;
} catch (networkError) {
// Network failure - fail open
console.error('Network error calling TinyScale:', networkError);
return true;
}
}
Fail Open vs Fail Closed
Fail open (recommended): If TinyScale is unavailable, allow the request.
// Fail open - don't block legitimate users
if (error) return true;
Fail closed: If TinyScale is unavailable, reject the request.
// Fail closed - strict enforcement
if (error) return false;
:::tip We recommend fail open for most use cases. Blocking legitimate users due to an infrastructure issue is worse than temporarily allowing extra requests. :::
Debugging
Include the request_id from error responses when contacting support:
Request ID: req_a1b2c3d4e5f6g7h8i9j0k1l2
You can also check response headers:
curl -i https://limiter.tinyscale.io/v1/check ...
# X-Request-Id: req_a1b2c3d4e5f6g7h8i9j0k1l2