Overview
The SDK raises errors through two related classes:
SdkError— thrown by SDK code itself (validation, configuration, deprecated paths, internal invariants). Always carries acode, astatus(HTTP-like), and an optionaloriginalError.AjaxError extends SdkError— thrown when an HTTP call to Bitrix24 fails. AddsrequestInfo(method,requestId, request params) so you can correlate with portal-side logs. Since v1.1.2 (#39),requestInfodoes not include the full request URL and credential-bearing fields insideparamsare redacted — the goal is to keep webhook secrets out oftoJSON()/toString()output.
Method-style results that don't throw — Call, CallList, Batch, BatchByChunk — surface failures through Result/AjaxResult: check .isSuccess and read .getErrorMessages(). FetchList, by contrast, does throw on failure (the generator can't complete partially).
import { SdkError, AjaxError } from '@bitrix24/b24jssdk'
try {
// …SDK calls
}
catch (error) {
if (error instanceof AjaxError) {
// network / portal-side failure; error.code is the Bitrix24 code
console.error(error.code, error.status, error.requestInfo?.method, error.requestInfo?.requestId)
}
else if (error instanceof SdkError) {
// SDK-side issue; error.code starts with JSSDK_
console.error(error.code, error.status)
}
else {
throw error
}
}
SdkError codes raised by the SDK
Codes are stable strings — match on them, don't parse messages.
REST-side codes that come back as AjaxError
Bitrix24 returns these in the error field of an HTTP response. The SDK lifts them into AjaxError.code verbatim — match on the string.
This is not exhaustive — Bitrix24 publishes the full method-specific list at apidocs.bitrix24.com. Anything not listed here passes through as-is on AjaxError.code.
Handling patterns
Distinguish SDK bugs from portal-side failures
AjaxError extends SdkError, so order the instanceof checks specifically-first:
// @check-ignore: top-level try/catch with return, not valid at module scope
import { AjaxError, SdkError } from '@bitrix24/b24jssdk'
try {
await $b24.actions.v2.call.make({ method: 'crm.deal.get', params: { id: 1 } })
}
catch (error) {
if (error instanceof AjaxError) {
// Portal-side: error.code is the Bitrix24 code (e.g. expired_token)
if (error.code === 'expired_token') return refreshAndRetry()
if (error.code === 'AUTHORIZE_ERROR') return showPermissionDenied()
throw error
}
if (error instanceof SdkError) {
// SDK-side: error.code starts with JSSDK_
throw error // these are programmer errors, surface them
}
throw error
}
// @check-ignore: top-level try/catch with return, not valid at module scope
import { AjaxError, SdkError } from '@bitrix24/b24jssdk'
try {
await $b24.actions.v3.call.make({ method: 'crm.deal.get', params: { id: 1 } })
}
catch (error) {
if (error instanceof AjaxError) {
// Portal-side: error.code is the Bitrix24 code (e.g. expired_token)
if (error.code === 'expired_token') return refreshAndRetry()
if (error.code === 'AUTHORIZE_ERROR') return showPermissionDenied()
throw error
}
if (error instanceof SdkError) {
// SDK-side: error.code starts with JSSDK_
throw error // these are programmer errors, surface them
}
throw error
}
Use isSuccess for non-throwing methods
Call, CallList, Batch, BatchByChunk return a Result / AjaxResult instead of throwing:
// @check-ignore: top-level return in callList error-handling illustration
const response = await $b24.actions.v2.callList.make({ /* … */ })
if (!response.isSuccess) {
console.error(response.getErrorMessages().join('; '))
return
}
const items = response.getData()
// @check-ignore: top-level return in callList error-handling illustration
const response = await $b24.actions.v3.callList.make({ /* … */ })
if (!response.isSuccess) {
console.error(response.getErrorMessages().join('; '))
return
}
const items = response.getData()
For batches with isHaltOnError: false, isSuccess flips false on any sub-call failure but getData() still contains the successful entries. Iterate and check per-row .isSuccess if you need to know which calls passed.
Catch around for await for FetchList
// @check-ignore: top-level for-await in fetchList error-handling illustration
try {
for await (const chunk of $b24.actions.v2.fetchList.make({ /* … */ })) {
await persist(chunk)
}
}
catch (error) {
if (
error instanceof SdkError
&& error.code === 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V2'
) {
// a page request failed; persisted chunks before this point are still good
return resumeFromLastSavedId()
}
throw error
}
// @check-ignore: top-level for-await in fetchList error-handling illustration
try {
for await (const chunk of $b24.actions.v3.fetchList.make({ /* … */ })) {
await persist(chunk)
}
}
catch (error) {
if (
error instanceof SdkError
&& error.code === 'JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V3'
) {
// a page request failed; persisted chunks before this point are still good
return resumeFromLastSavedId()
}
throw error
}
Decide what to retry
See also
- Choosing the right method — picks the right primitive before you have to read this page.
- Restrictions System — rate limit, operating-time and adaptive delay configuration.
AjaxResult— full payload surface (isSuccess,getData,getErrorMessages). The v2-only paging helpersisMore,hasMore,getNext,fetchNextandgetTotalare deprecated and slated for removal in 2.0.0; useb24.actions.v{2,3}.callList.makeorfetchList.makeinstead.getNext()continues to throwJSSDK_CORE_METHOD_NOT_SUPPORT_IN_API_V3against v3 clients.