Skip to main content

Error Handling

View as Markdown

Error Handling

What the SDK throws, when, and how to catch it.

What actually throws

SituationThrown
Bad API key / credentials during login or connectAuthenticationException
Transport loss and connection failures (including during login)ConnectionException
Data-pipe errors (open / write / close)PipeException
A login superseded, logged out, or detached mid-flightLoginAttemptCancelledError
Most argument and server-rejection errors (use(), getService(), DAP failures)plain Error
sendFiles with a non-positive maxConcurrentRangeError
Answer.getJson() on non-JSON contentthrows
import { RocketRideClient, AuthenticationException, ConnectionException, LoginAttemptCancelledError } from 'rocketride';

try {
await client.connect();
const { token } = await client.use({ filepath: './pipeline.pipe' });
await client.send(token, data);
} catch (e) {
if (e instanceof AuthenticationException) {
console.error('Bad credentials');
} else if (e instanceof LoginAttemptCancelledError) {
console.log('Login cancelled:', e.reason); // 'superseded' | 'logout' | 'detached'
} else if (e instanceof ConnectionException) {
console.error('Connection failed:', e.message);
} else {
console.error('Request failed:', e);
}
}

AuthenticationException is thrown on DAP auth failure. In persist mode the client calls onConnectError and does not retry authentication — fix credentials and call login() or connect() again.

LoginAttemptCancelledError extends Error directly (intentionally not a RocketRideException). Its reason is the LoginAttemptCancellationReason union 'superseded' | 'logout' | 'detached' — catch it when overlapping lifecycle actions are expected. An unsolicited transport loss during login rejects with ConnectionException instead. See Concurrent logins.

The hierarchy

The full hierarchy is exported from rocketride:

DAPException                    # Base DAP protocol error
└── RocketRideException # Base for all RocketRide errors
├── ConnectionException # Connection/network issues
│ └── AuthenticationException # Bad API key or credentials
├── PipeException # Data pipe errors
├── ExecutionException # Reserved: defined but not currently thrown
└── ValidationException # Reserved: defined but not currently thrown

LoginAttemptCancelledError # extends Error directly (by design)

Exceptions in the hierarchy expose a dapResult record with the server's error context (mirroring Python's dap_result), plus two optional fields:

  • code — the server's machine-readable classification, absent when the failure has none. Task failures carry one: TASK_NOT_REGISTERED (the token names no live task — never started, terminated, replaced, or the engine restarted), TASK_AMBIGUOUS, TASK_COMPLETED, TASK_STOPPED. Classify on code, not on message, which is written for people and may be reworded.
  • hint — troubleshooting text the SDK attached for a developer, absent when there is none. Kept out of message so an application can show the message to an end user without the developer checklist.
try {
await pipe.open();
} catch (err) {
if (err instanceof PipeException) {
if (err.code === 'TASK_NOT_REGISTERED') await restartPipeline();
else console.error(err.message, err.hint);
}
}

In practice most failures outside the connection/pipe paths surface as plain Error with a descriptive message — write handlers that catch the specific classes above first and fall back to Error. ExecutionException and ValidationException exist and are exported but the SDK does not currently throw them; don't write handlers that rely on them.