v2.2.0

Error-handling cookbook

Demonstrates the four error layers (SdkError / AjaxError / network / soft) and the hardErrorCodes / softErrorCodes / retryOnNetworkError knobs on the restriction manager.

What it does

Shows the canonical error-handling shape for SDK callers:

  1. SdkError — programming bug (e.g. calling a non-v3 method via actions.v3.*).
  2. AjaxError — REST returned an error (ERROR_NOT_FOUND, INVALID_CREDENTIALS, EXPIRED_TOKEN, QUERY_LIMIT_EXCEEDED, …).
  3. Network-levelNETWORK_ERROR / REQUEST_TIMEOUT. Critically different for non-idempotent calls.
  4. Soft errors — codes surfaced as isSuccess: false instead of thrown, either because they are pinned in the built-in list, because you added them via softErrorCodes, or — on restApi:v3 — because the category rule covers them.

Also covers setRestrictionManagerParams with the new knobs:

  • hardErrorCodes — extend the SDK's "throw immediately, no retry" list with app-specific codes.
  • softErrorCodes — extend the "return as soft error in AjaxResult" list.
  • retryOnNetworkError: false — disable network retry for *.add / *.update / file uploads to avoid duplicates.

On restApi:v3 the soft/hard split is decided from the response rather than from a list of codes, so an error the SDK has never heard of is still delivered like its neighbours — see Error Codes. That was opt-in through 2.x; since 3.0.0 it needs no parameter.

Stack

Node.js 20+. No external dependencies.

Environment

export B24_HOOK='https://your.bitrix24.com/rest/1/secret'

Run

npx tsx 10-error-handling.ts

Source

skills/b24jssdk-recipes/examples/10-error-handling.ts.

Notes

  • setRestrictionManagerParams updates the policy for all HTTP clients on this $b24 instance (both v2 and v3).
  • It replaces the parameters you name and keeps the rest, so restoring defaults means naming what you want cleared: ParamsFactory.getDefault() carries no hardErrorCodes / softErrorCodes key, and spreading it alone leaves those lists in force. The recipe's finally passes hardErrorCodes: [] for exactly that reason.
  • hardErrorCodes and softErrorCodes are additive — built-in lists (auth/fatal codes) are always hard. You can extend, you can't remove.
  • For non-idempotent calls, prefer wrapping each call in a try/finally that restores retryOnNetworkError: true afterwards. The recipe shows this pattern.
  • When a network timeout happens for a non-idempotent call, the safe action is reconcile (query for the just-created entity by a client-side idempotency tag), not retry.