Error Handling

How the nXus SDK surfaces errors, what each field means, and how to handle authentication failures, validation errors, rate limits, and QuickBooks connection issues.

Error shape

The HTTP API can return a StandardErrorResponse envelope or problem details. Public resource clients normalize supported responses and throw NxusApiError in TypeScript/Python or NxusApiException in .NET. Successful lists return a page; other CRUD methods return the resource or acknowledgement directly. There is no { data, error } result to inspect after a public resource call.

error-response.json
1234567891011
{
"error": {
  "message": "The provided API key is invalid or has been revoked.",
  "userFacingMessage": "Your API key is no longer valid. Create or rotate a key and try again.",
  "type": "AUTHENTICATION_ERROR_TYPE",
  "code": "API_KEY_INVALID",
  "httpStatusCode": 401,
  "integrationCode": null,
  "requestId": "req_abc123"
}
}

Raw HTTP fields and normalized SDK properties have different names:

Raw HTTP fieldTypeScriptPython.NET
error.userFacingMessageuserMessageuser_messageUserMessage
error.httpStatusCodestatusstatusStatus
error.codecodecodeCode
error.typetypetypeErrorType
error.requestIdrequestIdrequest_idRequestId
error.integrationCodeintegrationCodeintegration_codeIntegrationCode
Validation errors mapvalidationErrorsvalidation_errorsValidationErrors
Retry delay when suppliedretryAfterretry_afterRetryAfter

Optional fields can be absent. Retry delays are in seconds. Raw problem details use status, detail, and title; validation details can accompany 400 or 422 responses. See the Error Responses reference for the wire contract and enum values pinned to SDK v1.0.

Using NxusApiError

Configure the client with your API key and select the company on each request. Catch typed errors at your application boundary. Rethrow unexpected programming or argument errors rather than swallowing them.

errors.ts
1234567891011121314151617181920212223
import { NxusClient, NxusApiError } from 'nxus-qbd';

const apiKey = process.env.NXUS_API_KEY;
if (!apiKey) throw new Error("Set NXUS_API_KEY");
const nxus = new NxusClient({ apiKey });

try {
  const page = await nxus.vendors.list(
    { limit: 50 }, { connectionId: "YOUR_CONNECTION_ID" },
  );
  console.log(page.data);
} catch (err) {
  if (!(err instanceof NxusApiError)) throw err;
  console.error(err.userMessage);
  console.error({ code: err.code, status: err.status, requestId: err.requestId });
  if (err.isValidationError) console.error(err.validationErrors);
  if (err.isConnectorOffline) console.error("Reconnect QuickBooks Web Connector.");
  if (err.isRestrictionError) console.error("Resolve connection or billing restrictions.");
  if (err.isRateLimited) console.error("Retry delay in seconds:", err.retryAfter);
  if (err.code === "QBD_STALE_EDIT_SEQUENCE") {
    console.error("Fetch the current revisionNumber before updating.");
  }
}

Boolean helpers

These are properties, not methods. Classifications can overlap; inspect the specific code before choosing a recovery action.

TypeScriptPython.NETMeaning
isAuthErroris_auth_errorIsAuthErrorAuthentication/authorization failure
isValidationErroris_validation_errorIsValidationErrorValidation code/type or field errors; not every 400/422
isRateLimitedis_rate_limitedIsRateLimited429 or RATE_LIMIT_EXCEEDED
isConnectorOfflineis_connector_offlineIsConnectorOfflineQWC_NOT_CONNECTED, QWC_NEVER_CONNECTED, or offline type
isRestrictionErroris_restriction_errorIsRestrictionErrorLifecycle/billing restriction
isConflictis_conflictIsConflictAny 409 or QBD_STALE_EDIT_SEQUENCE; not a blanket retry signal
isNotFoundis_not_foundIsNotFoundMissing resource
isIntegrationErroris_integration_errorIsIntegrationErrorQuickBooks integration code is present

Status code reference

StatusAction
400, 422Correct invalid input and inspect the field errors.
401, 403Check credentials and permissions.
402Resolve billing or the reported lifecycle restriction.
404Verify the resource ID and target company.
405Check the endpoint’s HTTP method.
408, 504Preserve an uncertain Create’s identity; it may still have completed.
409Inspect the code and retry signal. Stale revisions and idempotency-key reuse require different fixes.
429Follow the server delay and bounded retry policy.
500, 502, 503Inspect the code, connector status, and request ID. Resolve offline/restriction conditions before resuming.

Rate limiting

Limits vary by endpoint and deployment. A 429 response can supply Retry-After and/or a supported body delay field. The SDK normalizes that guidance into its retry-delay property when available.

The SDK already performs bounded automatic retries. Its default budget is two retries (up to three total attempts for an eligible initial request). Configure this budget instead of adding a second automatic loop around it. The transport honors x-should-retry and server delay guidance. Long delays can be surfaced for application scheduling rather than waited out within the SDK.

retry.ts
12345678910111213141516171819
import { NxusApiError, NxusClient } from "nxus-qbd";

const apiKey = process.env.NXUS_API_KEY;
if (!apiKey) throw new Error("Set NXUS_API_KEY before running this example.");
const client = new NxusClient({ apiKey });

try {
  const page = await client.vendors.list(
    { limit: 5 },
    { connectionId: "conn_abc123", maxRetries: 2 }, // three attempts total
  );
  console.log("Fetched " + page.data.length + " vendors.");
} catch (error) {
  if (error instanceof NxusApiError && error.isRateLimited) {
    console.error("Rate limited; retry after " + (error.retryAfter ?? "an unspecified delay") + " seconds.");
  } else {
    throw error;
  }
}

Pagination continuation requests and Delete/void operations default to no retries. If a continuation fails, discard the cursor and restart from page 1 instead of blindly repeating a request against that stateful cursor.

Recovering Create requests

Supported generic Create methods attach a stable Idempotency-Key across automatic attempts. Persist your own key, connection ID, and unchanged payload when a workflow can resume later. Protected Creates can also retry local HTTP timeouts within their budget; this does not apply to every POST.

A timeout does not prove that QuickBooks failed to create the record. Reusing the key with a changed payload can produce 409 IDEMPOTENCY_KEY_REUSED, which is different from QBD_STALE_EDIT_SEQUENCE. See Error Recovery for supported operations and recovery limits. HTTP timeout and server queue timeout are distinct budgets; see the Latency Model.

Input sanitization

The nXus API sanitizes all string values before sending them to QuickBooks Desktop. This means the value you submit may differ slightly from what QuickBooks stores.

What the API does:

  1. Unicode normalization — accented characters are decomposed to their base form (e.g. café → cafe, müller → muller).
  2. Smart quote replacement — typographic quotes and dashes are converted to their ASCII equivalents (e.g. "word" → "word", — → -).
  3. Non-printable character removal — control characters, zero-width characters, and non-ASCII symbols are stripped.
  4. Non-Latin script removal — characters outside printable ASCII (0x20–0x7E) are dropped after normalization.

Why this matters: If your application stores the original input and compares it against the value returned from QuickBooks, you may see mismatches. Always use the value returned by the API as the source of truth after a create or update operation.

Affected fields: All user-supplied text fields — names, addresses, memos, notes, descriptions, and custom field values.


Handling patterns

Display the normalized user-facing message and retain the request ID, status, code, and developer message in diagnostic logs. Map validation field keys to your form inputs when details are available. Field names can follow the server’s request naming conventions.

QuickBooks-specific errors

integrationCode

This optional field contains an HRESULT or qbXML status detail when the failure originates in QuickBooks. Connector-offline and policy failures can still be actionable without it. Display the normalized user-facing message and inspect the specific error classification.

Stale edit sequence (409)

QuickBooks uses an edit sequence internally. The public SDK exposes it as revisionNumber (Python: revision_number). For QBD_STALE_EDIT_SEQUENCE, retrieve the record again and submit its current revision number with the update. Other 409 errors can represent business conflicts or idempotency-key misuse; isConflict alone does not authorize retrying them.

Testing your error handling

Use a test connection to check credential, validation, connector-offline, and restriction messages. Use mocked responses for repeatable retry-delay tests without generating bursts of live traffic. Verify that unknown errors propagate and uncertain Creates retain their original identity.

Further reading