Error Handling
The driver throws strongly-typed exceptions inheriting from the base BastionError class.
1. Catching Errors
import {
BastionClient,
BastionError,
NotFoundError,
QuotaExceededError,
PasswordChangeRequiredError,
BastionAuthError,
} from "@liorans3/driver";
const client = new BastionClient("bastion://admin:YOUR_PASSWORD@127.0.0.1:27118");
const bucket = client.bucket("documents");
try {
const obj = await bucket.get("missing-report.pdf");
await obj.writeToFile("./report.pdf");
} catch (error: unknown) {
if (error instanceof NotFoundError) {
console.error("The requested object or bucket does not exist.");
} else if (error instanceof QuotaExceededError) {
console.error("Bucket storage quota has been reached.");
} else if (error instanceof PasswordChangeRequiredError) {
console.error("Bootstrap admin password must be changed before proceeding.");
} else if (error instanceof BastionAuthError) {
console.error("Invalid username, password, or access key secret.");
} else if (error instanceof BastionError) {
console.error(`API Error [${error.code}] (HTTP ${error.status}): ${error.message}`);
} else {
console.error("Unexpected failure:", error);
}
}
2. Error Class Hierarchy
All errors extend BastionError, which provides:
error.code: Server error code string (e.g."object_not_found").error.status: HTTP status code integer (e.g.404).error.message: Human-readable error description.error.isRetryable: Boolean indicating if the operation can be retried safely.
BastionError (Base)
├── BastionAuthError (HTTP 401)
├── PasswordChangeRequiredError (HTTP 403)
├── BastionForbiddenError (HTTP 403)
├── NotFoundError (HTTP 404)
├── AlreadyExistsError (HTTP 409)
├── InvalidInputError (HTTP 400)
├── ConnectionError (Network / DNS / Socket Failure)
├── RangeNotSatisfiableError (HTTP 416)
├── QuotaExceededError (HTTP 507)
└── StorageCapacityExhaustedError (HTTP 507)
3. Server Error Code Mapping
| Error Class | HTTP Status | Server Error Code (code) | Meaning |
|---|---|---|---|
BastionAuthError | 401 Unauthorized | invalid_credentials, unauthorized | Missing, incorrect, or expired credentials. |
PasswordChangeRequiredError | 403 Forbidden | password_change_required | Bootstrap admin account must rotate initial password. |
BastionForbiddenError | 403 Forbidden | forbidden | Authenticated role lacks required permission. |
NotFoundError | 404 Not Found | bucket_not_found, object_not_found, user_not_found, upload_not_found, access_key_not_found | Target resource does not exist. |
AlreadyExistsError | 409 Conflict | bucket_already_exists, user_already_exists | Entity with this name already exists. |
InvalidInputError | 400 Bad Request | invalid_input, invalid_uri | Malformed parameters, invalid key format, or bad range. |
QuotaExceededError | 507 Insufficient Storage | quota_exceeded | Bucket byte quota limit exceeded. |
StorageCapacityExhaustedError | 507 Insufficient Storage | storage_capacity_exhausted | Host storage disk below minimum safety watermark. |
RangeNotSatisfiableError | 416 Range Not Satisfiable | range_not_satisfiable | Requested byte offset exceeds total object size. |
ConnectionError | 0 (Client-side) | connection_error | Connection refused, timeout, or network disconnect. |
4. Retry Guidelines
The driver flags transient network failures and 5xx server errors with isRetryable = true.
async function fetchWithRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
let attempt = 0;
while (true) {
try {
return await fn();
} catch (err) {
attempt++;
if (err instanceof BastionError && err.isRetryable && attempt < maxRetries) {
const backoffMs = Math.pow(2, attempt) * 200;
await new Promise((res) => setTimeout(res, backoffMs));
continue;
}
throw err;
}
}
}