Errors
All Urblock API errors follow a consistent format. Error responses include a type, a machine-readable code, a human-readable message, and the HTTP status.
Error Response Format
{
"error": {
"type": "invalid_request_error",
"code": "token_not_found",
"message": "No token found with id tok_xyz.",
"param": "token_id",
"status": 404
}
}
| Field | Type | Description |
|---|---|---|
type | string | Error category (see Error Types) |
code | string | Machine-readable error code |
message | string | Human-readable explanation |
param | string | null | The parameter that caused the error (if applicable) |
status | number | HTTP status code |
Error Types
| Type | HTTP Status | When |
|---|---|---|
invalid_request_error | 400, 404, 409, 422 | Invalid parameters, missing fields, resource not found, conflicts |
authentication_error | 401 | Missing, invalid, or expired API key / JWT |
authorization_error | 403 | Insufficient permissions or wrong key type |
rate_limit_error | 429 | Too many requests |
api_error | 500 | Internal server error (transient — safe to retry) |
Common Error Codes
Authentication & Authorization
| Code | Type | Status | Description |
|---|---|---|---|
invalid_api_key | authentication_error | 401 | API key is invalid or revoked |
secret_key_required | authorization_error | 403 | Write operation requires sk_ key |
token_expired | authentication_error | 401 | JWT access token has expired |
invalid_refresh_token | authentication_error | 401 | Refresh token is invalid or revoked |
scope_insufficient | authorization_error | 403 | API key lacks the required scope |
Validation
| Code | Type | Status | Description |
|---|---|---|---|
validation_error | invalid_request_error | 400 | Request body or query params failed validation |
invalid_address | invalid_request_error | 400 | Not a valid Ethereum address |
invalid_amount | invalid_request_error | 400 | Amount must be a positive numeric string |
invalid_network | invalid_request_error | 400 | Unsupported network slug |
Resource Not Found
| Code | Type | Status | Description |
|---|---|---|---|
token_not_found | invalid_request_error | 404 | Token ID does not exist |
wallet_not_found | invalid_request_error | 404 | Wallet ID does not exist |
transaction_not_found | invalid_request_error | 404 | Transaction ID does not exist |
vesting_not_found | invalid_request_error | 404 | Vesting schedule not found |
vault_not_found | invalid_request_error | 404 | Vault not found |
governance_not_found | invalid_request_error | 404 | Governance instance not found |
Conflicts & Business Logic
| Code | Type | Status | Description |
|---|---|---|---|
duplicate_idempotency_key | invalid_request_error | 409 | Idempotency key reused with different params |
token_not_deployed | invalid_request_error | 409 | Token not yet deployed |
already_frozen | invalid_request_error | 409 | Address is already frozen |
insufficient_balance | invalid_request_error | 422 | Sender has insufficient balance |
Rate Limiting
| Code | Type | Status | Description |
|---|---|---|---|
rate_limit_exceeded | rate_limit_error | 429 | Too many requests — check Retry-After header |
SDK Error Handling
try {
const token = await urblock.tokens.get("tok_nonexistent");
} catch (err) {
if (err.type === "invalid_request_error") {
console.log(`Not found: ${err.message}`);
// → "Not found: No token found with id tok_nonexistent."
} else if (err.type === "rate_limit_error") {
const retryAfter = err.headers?.["retry-after"];
console.log(`Rate limited — retry in ${retryAfter}s`);
} else {
throw err; // Unexpected error
}
}
Retry Logic
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (err: any) {
if (err.status === 429) {
const delay = parseInt(err.headers?.["retry-after"] ?? "5") * 1000;
await new Promise(r => setTimeout(r, delay));
continue;
}
if (err.status >= 500) {
await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
continue;
}
throw err; // 4xx errors are not retryable
}
}
throw new Error("Max retries exceeded");
}
// Usage
const token = await withRetry(() => urblock.tokens.get("tok_abc123"));
HTTP Status Code Summary
| Status | Meaning | Retryable? |
|---|---|---|
| 200 | Success | — |
| 201 | Created | — |
| 400 | Bad Request | No — fix the request |
| 401 | Unauthorized | No — check API key |
| 403 | Forbidden | No — check permissions |
| 404 | Not Found | No — resource doesn't exist |
| 409 | Conflict | No — check idempotency key or state |
| 422 | Unprocessable | No — business logic error |
| 429 | Rate Limited | Yes — wait for Retry-After |
| 500 | Internal Error | Yes — exponential backoff |
Next Steps
- Rate Limiting — understand rate limit headers and backoff
- Idempotency — prevent duplicate operations
- Authentication — authentication error scenarios
- API Overview — response format and conventions