VeztaVezta

Error Codes

Standardized error response format and codes

All API errors return a consistent JSON structure. The GlobalExceptionFilter normalizes every error -- including validation errors, domain exceptions, and unhandled crashes -- into this format.

Response Format

{
  "statusCode": 400,
  "code": "VALIDATION_ERROR",
  "message": "Field 'amount' must be a positive number"
}
FieldTypeDescription
statusCodenumberHTTP status code (400, 401, 403, 404, 429, 500)
codestringMachine-readable error code for programmatic handling
messagestringHuman-readable description of the error

Error Codes by Status

400 Bad Request

CodeDescriptionExample
VALIDATION_ERRORRequest body failed DTO validationMissing required field, invalid type, value out of range
NONCE_EXPIREDAuth nonce expired or not foundWallet verification took too long, nonce was consumed
ORDER_FAILEDOrder could not be placedInsufficient balance, market closed, invalid order parameters
SELF_REFERRALUser tried to use their own access keyReferral code belongs to the authenticated user
INVALID_CODE_FORMATAccess key format is invalidCode must be 4-12 alphanumeric characters
INSUFFICIENT_BALANCENot enough funds for the operationPaper trading balance too low, merge/split insufficient shares

401 Unauthorized

CodeDescriptionExample
UNAUTHORIZEDMissing or invalid JWT tokenNo Bearer token, expired access token
INVALID_SIGNATUREWallet signature verification failedSignature does not match the expected message
INVALID_REFRESH_TOKENRefresh token is invalid or expiredToken was revoked, rotated, or past its 7-day TTL

403 Forbidden

CodeDescriptionExample
FORBIDDENUser does not have permissionAccessing another user's resource, insufficient tier
NOT_ELIGIBLEUser is not eligible for the actionCannot generate access key, mission requirements not met

404 Not Found

CodeDescriptionExample
NOT_FOUNDResource does not existMarket, order, or user not found
USER_NOT_FOUNDUser account not foundWallet address has no associated account
MARKET_NOT_FOUNDMarket does not existInvalid market slug or ID
ORDER_NOT_FOUNDOrder does not existAttempting to cancel a nonexistent order
MISSION_NOT_FOUNDMission does not existInvalid mission ID

409 Conflict

CodeDescriptionExample
ALREADY_REFERREDUser already has a referralCannot apply a second referral code
CODE_TAKENAccess key code already in useAnother user has claimed this custom code

429 Too Many Requests

CodeDescriptionExample
RATE_LIMITEDRequest rate limit exceededMore than 100 requests per minute from the same IP

500 Internal Server Error

CodeDescriptionExample
INTERNAL_ERRORUnexpected server errorUnhandled exception, database connection failure

Validation Errors

When request body validation fails via class-validator, the GlobalExceptionFilter joins all validation messages into a single comma-separated string and forces the code to VALIDATION_ERROR:

{
  "statusCode": 400,
  "code": "VALIDATION_ERROR",
  "message": "amount must be a positive number, side must be one of: YES, NO"
}

The validation pipe is configured with whitelist: true (strips unknown properties), transform: true (auto-coerces types), and forbidNonWhitelisted: true (rejects unknown fields).

How Errors Are Generated

Domain Errors

Backend services throw ApiException for business logic errors with a specific code:

throw new ApiException(
  'ORDER_FAILED',
  'Insufficient balance to place this order',
  HttpStatus.BAD_REQUEST,
);

Default Code Mapping

When an error does not include an explicit code (e.g., a raw HttpException), the GlobalExceptionFilter maps the HTTP status to a default code:

StatusDefault Code
400VALIDATION_ERROR
401UNAUTHORIZED
403FORBIDDEN
404NOT_FOUND
429RATE_LIMITED
OtherINTERNAL_ERROR

Client-Side Handling

The frontend API client (lib/api/client.ts) throws an ApiClientError with the full error body. Handle errors by checking the code field:

try {
  await placeOrder(orderData);
} catch (error) {
  if (error instanceof ApiClientError) {
    switch (error.body.code) {
      case 'ORDER_FAILED':
        showToast('Order failed: ' + error.body.message);
        break;
      case 'UNAUTHORIZED':
        // 401 retry is handled automatically by the client
        break;
      default:
        showToast('Something went wrong');
    }
  }
}

The API client automatically handles 401 errors by refreshing the access token and retrying the request. You do not need to handle UNAUTHORIZED errors manually in most cases.

On this page