NodeJS

Error Handling

Error types and error handling patterns in Node.js SDK

The SDK uses a hierarchical error system. All errors extend SSIError, which extends the standard Error.

Error Classes

Error ClassExtendsDescription
SSIErrorErrorBase error — has message, code, statusCode, responseBody (secrets redacted), headers
APIErrorSSIErrorAPI returned an error. code is the server error code, the HTTP status is in statusCode. An HTTP 200 carrying a code other than 200/204 also throws APIError
DuplicateRequestErrorAPIErrorHTTP 409: clientRequestId or batchRequestId already used (see Batch Orders)
AuthenticationErrorSSIErrorAuthentication failed (wrong credentials, token expired). Does not extend APIError
SmartOTPPendingErrorAuthenticationErrorSmart OTP not approved yet (HTTP 202, code 401114)
SmartOTPRejectedErrorAuthenticationErrorSmart OTP was rejected
ReauthenticationRequiredAuthenticationErrorThe session cannot be refreshed and no OTP was given: authenticate again with an OTP
RateLimitErrorSSIErrorRate limit exceeded — has retryAfterMs (milliseconds), limit, remaining, reset
WebSocketErrorSSIErrorWebSocket connection or communication error
TradingWSErrorWebSocketErrorThe Trading WebSocket server returned an error frame — has status, errorCode, serverMessage
ValidationErrorSSIErrorInput validation error
ConfigurationErrorSSIErrorConfiguration error (including an unknown option)

Import

import {
  SSIError,
  APIError,
  DuplicateRequestError,
  AuthenticationError,
  SmartOTPPendingError,
  SmartOTPRejectedError,
  ReauthenticationRequired,
  RateLimitError,
  WebSocketError,
  TradingWSError,
  ValidationError,
  ConfigurationError,
} from '@ssi.developer/ssi-sdk';

Basic Usage

try {
  const token = await auth.authenticate('wrong_otp');
} catch (error) {
  console.error(`Error: ${error.message}`);
}

Detailed Error Handling

AuthenticationError is not an APIError, so the order of the instanceof branches no longer matters between those two classes. Subclasses (DuplicateRequestError, TradingWSError, SmartOTP*) must be checked before their parent if you want to handle them separately.

try {
  const result = await trading.trading.placeLimitOrder(
    'YOUR_ACCOUNT_NO', 'SSI', OrderSide.BUY, 100, 68000,
  );
} catch (error) {
  if (error instanceof ReauthenticationRequired) {
    console.log('Need to re-authenticate with an OTP');
  } else if (error instanceof AuthenticationError) {
    console.log('Authentication failed');
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited, retry after ${error.retryAfterMs}ms`);
  } else if (error instanceof DuplicateRequestError) {
    console.log(`Duplicate id (HTTP 409): ${error.message}`);
  } else if (error instanceof APIError) {
    console.log(`API error ${error.statusCode} (code ${error.code}): ${error.message}`);
  } else if (error instanceof ValidationError) {
    console.log(`Validation: ${error.message}`);
  } else if (error instanceof TradingWSError) {
    console.log(`Trading WS: status=${error.status} code=${error.errorCode} msg=${error.serverMessage}`);
  } else if (error instanceof WebSocketError) {
    console.log(`WebSocket: ${error.message}`);
  } else if (error instanceof ConfigurationError) {
    console.log(`Config: ${error.message}`);
  } else if (error instanceof SSIError) {
    console.log(`SDK error: ${error.message}`);
  } else {
    console.log(`Unknown error: ${error}`);
  }
}

Error Properties

SSIError / APIError

PropertyTypeDescription
messagestringError message
codestring | number?Error code (for APIError, the server's code)
statusCodenumber?HTTP status code
responseBodyunknown?Raw response body (if available), secrets redacted
headersRecord<string, string>Response headers

RateLimitError

PropertyTypeDescription
messagestringError message
retryAfterMsnumber?Time to wait before retry (milliseconds). Formerly named retryAfter (seconds)
limit, remaining, resetnumber?Rate limit info sent by the server (if present)

code defaults to 'RATE_LIMITED' and statusCode is 429. For GET requests the REST client waits by itself on a 429 (at most 3 retries, never waiting longer than 30 seconds).

TradingWSError

PropertyTypeDescription
statusnumberStatus code in the error frame (for example 429)
errorCodestringServer error code
serverMessagestringServer message

Errors by feature

Batch Orders

For usage see API Services, section 5.6.

ErrorWhenWhat to do
ValidationErrorEmpty batch, over maxBatchOrders, or one bad order (missing field, clientRequestId too long, a cancel item without exactly one id...)Fix the input. No request was sent
DuplicateRequestErrorHTTP 409: clientRequestId or batchRequestId already used todayCheck the order book, do not resend under a different id
AuthenticationErrorAuthentication failed (wrong credentials, token expired)Authenticate again with an OTP
RateLimitErrorRequest rate exceededWait, then retry in a controlled way
APIErrorOther server errors (has statusCode, code), for example 400111 when batchRequestTime is outside the replay windowRead code and message, do not retry blindly

A batch is never retried automatically.

Trading WebSocket

See API Services, section 7.4.

ErrorWhen
TradingWSErrorThe server returned an error frame, or refused the connection after accepting the socket (HTTP 101). Has status, errorCode, serverMessage. Extends WebSocketError
WebSocketErrorNot connected, send failed, response timeout (not retried), socket closed before a response, or a missing private key for a state-changing command
ValidationErrorBad input caught locally (for example subscribing several accounts, an empty or over-limit batch). Since the methods are async, the Promise is rejected

A server status 429 becomes a TradingWSError with status 429. Rejected-signature codes 401006, 401008, 401013 are retried once by the SDK in signatureEncoding: 'auto' mode.

Error Handling Guidelines

  • Use instanceof to handle each error type.
  • Catch AuthenticationError when you need to refresh tokens or get a new OTP. ReauthenticationRequired means you must authenticate again with an OTP.
  • Catch RateLimitError and respect retryAfterMs for backoff.
  • Catch APIError to handle business errors from the server. Codes 401101-401104 and 401106-401108 (refresh token unusable) force re-authentication.
  • Catch WebSocketError when handling streaming connections. A failed first connect() throws WebSocketError or AuthenticationError.
  • Catch ValidationError to check input before calling API.
  • Catch ConfigurationError when configuration is missing or invalid.
  • Use SSIError as a fallback for all SDK errors.

On this page