Errors
BuddyError hierarchy — catch with instanceof, no string matching.
Every error thrown by the SDK extends BuddyError. Subclass with instanceof — no string code matching.
Hierarchy
BuddyError (extends Error)
├─ AuthenticationError HTTP 401 / 403
├─ APIError Other non-2xx API responses
├─ NetworkError Fetch failed (offline, DNS, etc.)
├─ TimeoutError Request exceeded the 30s timeout
├─ InvalidRequestError Invalid SDK usage / malformed request
└─ SessionError Session-lifecycle error (e.g. speak before connect) Fields on BuddyError
| Field | Type | Notes |
|---|---|---|
message | string | Human-readable reason |
statusCode | number \| undefined | HTTP status when applicable |
details | Record<string, unknown>? | Raw response body or extra context |
name | string | Class name — e.g. 'AuthenticationError' |
Catching
import {
BuddyError,
AuthenticationError,
APIError,
NetworkError,
TimeoutError,
InvalidRequestError,
SessionError
} from '@juspay/breeze-buddy-client-sdk';
try {
const session = await client.startSession({ templateId, payload });
} catch (err) {
if (err instanceof AuthenticationError) {
await refreshTokenAndRetry();
return;
}
if (err instanceof NetworkError || err instanceof TimeoutError) {
return showRetryBanner();
}
if (err instanceof APIError) {
console.error(err.statusCode, err.details);
return showApiErrorUI(err);
}
if (err instanceof BuddyError) {
// Catch-all for any other SDK error
console.error(err.message);
return showGenericError(err.message);
}
// Unknown — re-throw
throw err;
} When each error is thrown
AuthenticationError
Thrown on HTTP 401 / 403 from the API. Your JWT is invalid, expired, or doesn’t have the requested reseller_id / merchant_id in its allow-list.
// Likely cause: token expired
if (err instanceof AuthenticationError) await refreshToken(); APIError
Thrown on any other non-2xx response (400, 404, 500, etc.). Check err.statusCode and err.details.
if (err instanceof APIError) {
if (err.statusCode === 404) return 'Template not found';
if (err.statusCode === 429) return 'Rate limited — retry later';
return `API error: ${err.message}`;
} NetworkError
Thrown when fetch() itself fails — offline, DNS failure, CORS, etc. Not an HTTP error (the request never got a response).
TimeoutError
Thrown when an HTTP request exceeds the 30 second timeout.
InvalidRequestError
Thrown by SDK-side validation — before hitting the network. Examples:
session.assistantSpeak('')— empty text rejected- Future: unknown execution mode, malformed options
SessionError
Thrown for session-lifecycle violations on the client side. Examples:
session.assistantSpeak(text)called before the session is'connected'session.sendMessage(...)called on a disconnected session- Session closes while an
await session.assistantSpeak(...)is still pending
Pattern: retry with auth refresh
async function startWithRefresh(client: BuddyClient, opts: StartSessionOptions) {
try {
return await client.startSession(opts);
} catch (err) {
if (err instanceof AuthenticationError) {
await refreshToken();
// Rebuild client with new token, retry once
const fresh = new BuddyClient({ ...clientOptions, auth: { token: newToken } });
return fresh.startSession(opts);
}
throw err;
}
} Pattern: retry network failures
async function withRetry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
const retriable = err instanceof NetworkError || err instanceof TimeoutError;
if (!retriable || i === attempts - 1) throw err;
await new Promise((r) => setTimeout(r, 2 ** i * 500));
}
}
throw new Error('unreachable');
}
const session = await withRetry(() => client.startSession({ templateId, payload })); Don't retry AuthenticationError