Comprehensive error handling system for Ledger hardware wallet applications and libraries
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Specialized error classes for Ledger device communication, including transport-level failures and device status code errors.
Generic transport error for device communication failures, such as incorrect data received or communication breakdowns.
/**
* TransportError is used for any generic transport errors.
* e.g. Error thrown when data received by exchanges are incorrect or if exchanged failed to communicate with the device for various reason.
* @param message - Error message describing the transport failure
* @param id - Identifier for the specific transport error
*/
function TransportError(message: string, id: string): void;Usage Examples:
import { TransportError } from "@ledgerhq/errors";
// Create transport error with specific ID
const usbError = new TransportError("USB device disconnected", "USB_DISCONNECT");
console.log(usbError.message); // "USB device disconnected"
console.log(usbError.id); // "USB_DISCONNECT"
console.log(usbError.name); // "TransportError"
// Handle in try-catch
try {
// Device communication operation
} catch (error) {
if (error instanceof TransportError) {
console.log(`Transport failed: ${error.message} (${error.id})`);
}
}Error thrown when a Ledger device returns a non-success status code, with automatic status code mapping and human-readable messages.
/**
* Error thrown when a device returned a non success status.
* the error.statusCode is one of the `StatusCodes` exported by this library.
* @param statusCode - The numeric status code returned by the device
*/
function TransportStatusError(statusCode: number): void;Usage Examples:
import { TransportStatusError, StatusCodes } from "@ledgerhq/errors";
// Create status error
const pinError = new TransportStatusError(StatusCodes.PIN_REMAINING_ATTEMPTS);
console.log(pinError.statusCode); // 0x63c0
console.log(pinError.statusText); // "PIN_REMAINING_ATTEMPTS"
console.log(pinError.message); // "Ledger device: PIN_REMAINING_ATTEMPTS (0x63c0)"
// Create error with unknown status code
const unknownError = new TransportStatusError(0x1234);
console.log(unknownError.statusText); // "UNKNOWN_ERROR"
console.log(unknownError.message); // "Ledger device: UNKNOWN_ERROR (0x1234)"
// Handle device errors
try {
// Device operation
} catch (error) {
if (error instanceof TransportStatusError) {
if (error.statusCode === StatusCodes.CONDITIONS_OF_USE_NOT_SATISFIED) {
console.log("User denied the operation");
} else if (error.statusCode === StatusCodes.SECURITY_STATUS_NOT_SATISFIED) {
console.log("Device is locked or access rights invalid");
}
}
}Comprehensive mapping of Ledger device status codes to numeric values for hardware-level error handling.
const StatusCodes: {
PIN_REMAINING_ATTEMPTS: 0x63c0;
INCORRECT_LENGTH: 0x6700;
MISSING_CRITICAL_PARAMETER: 0x6800;
COMMAND_INCOMPATIBLE_FILE_STRUCTURE: 0x6981;
SECURITY_STATUS_NOT_SATISFIED: 0x6982;
CONDITIONS_OF_USE_NOT_SATISFIED: 0x6985;
INCORRECT_DATA: 0x6a80;
NOT_ENOUGH_MEMORY_SPACE: 0x6a84;
REFERENCED_DATA_NOT_FOUND: 0x6a88;
FILE_ALREADY_EXISTS: 0x6a89;
INCORRECT_P1_P2: 0x6b00;
INS_NOT_SUPPORTED: 0x6d00;
CLA_NOT_SUPPORTED: 0x6e00;
TECHNICAL_PROBLEM: 0x6f00;
OK: 0x9000;
MEMORY_PROBLEM: 0x9240;
NO_EF_SELECTED: 0x9400;
INVALID_OFFSET: 0x9402;
FILE_NOT_FOUND: 0x9404;
INCONSISTENT_FILE: 0x9408;
ALGORITHM_NOT_SUPPORTED: 0x9484;
INVALID_KCV: 0x9485;
CODE_NOT_INITIALIZED: 0x9802;
ACCESS_CONDITION_NOT_FULFILLED: 0x9804;
CONTRADICTION_SECRET_CODE_STATUS: 0x9808;
CONTRADICTION_INVALIDATION: 0x9810;
CODE_BLOCKED: 0x9840;
MAX_VALUE_REACHED: 0x9850;
GP_AUTH_FAILED: 0x6300;
LICENSING: 0x6f42;
HALTED: 0x6faa;
};Usage Examples:
import { StatusCodes, TransportStatusError } from "@ledgerhq/errors";
// Check specific status codes
if (statusCode === StatusCodes.OK) {
console.log("Operation successful");
} else if (statusCode === StatusCodes.CONDITIONS_OF_USE_NOT_SATISFIED) {
throw new TransportStatusError(statusCode);
}
// Use in switch statement
switch (statusCode) {
case StatusCodes.SECURITY_STATUS_NOT_SATISFIED:
return "Device locked or invalid access rights";
case StatusCodes.CONDITIONS_OF_USE_NOT_SATISFIED:
return "Operation denied by user";
case StatusCodes.INCORRECT_DATA:
return "Invalid data received";
default:
return "Unknown device error";
}
// Convert to hex for logging
console.log(`Status: 0x${StatusCodes.PIN_REMAINING_ATTEMPTS.toString(16)}`);
// "Status: 0x63c0"Returns human-readable error messages for common Ledger device status codes.
/**
* Returns human-readable message for status codes
* @param code - The numeric status code
* @returns Human-readable message or undefined/null if no mapping exists
*/
function getAltStatusMessage(code: number): string | undefined | null;Usage Examples:
import { getAltStatusMessage, StatusCodes } from "@ledgerhq/errors";
// Get human-readable messages
console.log(getAltStatusMessage(StatusCodes.INCORRECT_LENGTH));
// "Incorrect length"
console.log(getAltStatusMessage(StatusCodes.SECURITY_STATUS_NOT_SATISFIED));
// "Security not satisfied (dongle locked or have invalid access rights)"
console.log(getAltStatusMessage(StatusCodes.CONDITIONS_OF_USE_NOT_SATISFIED));
// "Condition of use not satisfied (denied by the user?)"
console.log(getAltStatusMessage(StatusCodes.INVALID_DATA));
// "Invalid data received"
// Handle technical problems (0x6f00-0x6fff range)
console.log(getAltStatusMessage(0x6f50));
// "Internal error, please report"
// Unknown status codes return undefined
console.log(getAltStatusMessage(0x1234)); // undefined
// Use in error handling
function handleStatusCode(code: number): string {
const altMessage = getAltStatusMessage(code);
if (altMessage) {
return altMessage;
}
const statusText = Object.keys(StatusCodes)
.find(k => StatusCodes[k] === code) || "UNKNOWN_ERROR";
return statusText;
}Additional transport-related error classes for specific transport layer issues.
const TransportOpenUserCancelled: CustomErrorFunc;
const TransportInterfaceNotAvailable: CustomErrorFunc;
const TransportRaceCondition: CustomErrorFunc;
const TransportWebUSBGestureRequired: CustomErrorFunc;
const BluetoothRequired: CustomErrorFunc;Usage Examples:
import {
TransportOpenUserCancelled,
TransportInterfaceNotAvailable,
TransportWebUSBGestureRequired,
BluetoothRequired
} from "@ledgerhq/errors";
// Handle user cancellation
try {
// Transport opening operation
} catch (error) {
if (error instanceof TransportOpenUserCancelled) {
console.log("User cancelled device connection");
}
}
// Check for interface availability
if (!isTransportAvailable) {
throw new TransportInterfaceNotAvailable("USB transport not available");
}
// WebUSB gesture requirement
throw new TransportWebUSBGestureRequired("User interaction required for WebUSB access");
// Bluetooth requirement
throw new BluetoothRequired("Bluetooth must be enabled for device connection");