SerialPilot

/02 — Reference

Errors & reliability

Every error SerialPilot throws is a strongly-typed subclass of SerialPilotError with a stable code, a human message, and an actionable advice string. You can match on the class, on the code, or on both.

Error shape

PropertyTypeNotes
codeSerialPilotErrorCodeStable enum-like string (e.g. 'PORT_NOT_FOUND').
messagestringHuman-readable description.
advicestringWhat to do about it.
pathstring?The port path involved, when known.
baudRatenumber?The baud rate, when known.
causeError?The underlying OS error, when one exists.

Error catalogue

CodeClassCauseRecovery
PORT_NOT_FOUNDPortNotFoundErrorPath wrong or device unplugged.Re-enumerate; use findPorts().
PERMISSION_DENIEDPermissionDeniedErrorOS denied access to the device.Linux: add user to dialout. macOS: grant in System Settings → Privacy.
PORT_BUSYPortBusyErrorAnother process holds the port.Close the other app (Arduino IDE, screen, PuTTY).
DISCONNECTEDDisconnectedErrorDevice unplugged mid-session.Use @serialpilot/reconnect for resilient sessions.
OPEN_FAILEDOpenFailedErrorGeneric open failure (often follows a more specific error).Inspect err.cause for the OS reason.
WRITE_FAILEDWriteFailedErrorWrote to a port that's gone.Check port.isOpen before writing in flaky environments.
READ_FAILEDReadFailedErrorRead from a port that's gone.Same as above.
CANCELLEDCancelledErrorAn in-flight operation was aborted.Expected when calling close() with pending I/O — usually safe to ignore.
INVALID_ARGUMENTInvalidArgumentErrorBad constructor args.Validate path and baudRate.
TIMEOUTTimeoutErrorOperation exceeded its budget (mostly from command-queue).Raise the timeout, retry, or check device responsiveness.

Catching

import {
SerialPilot,
SerialPilotError,
PortNotFoundError,
PermissionDeniedError,
PortBusyError,
DisconnectedError,
} from 'serialpilot'

try { const port = new SerialPilot({ path: ‘/dev/ttyUSB0’, baudRate: 9600 }) } catch (err) { if (err instanceof PortNotFoundError) { console.error(err.advice) } else if (err instanceof PermissionDeniedError) { console.error(err.advice) } else if (err instanceof SerialPilotError) { console.error(${err.code}: ${err.message}) console.error(Advice: ${err.advice}) } }

Error events

Asynchronous failures arrive on the port's error event. Always attach a listener — an unhandled stream error crashes the Node process.

port.on('error', err => {
if (err instanceof DisconnectedError) {
// trigger reconnect
} else {
log.error({ code: err.code, advice: err.advice }, err.message)
}
})

Reliability strategies

  • Auto-reconnect. Wrap your port with SerialPilotReconnect in production. It handles cable yanks, USB-path reshuffles, and exponential backoff.
  • Open-by-device. Use SerialPilot.openByDevice({ vendorId, productId }) instead of pinning to a path — paths shift between hosts and OSes.
  • Honour backpressure. If port.write() returns false, wait for 'drain'. Continually writing past the high-water mark causes ballooning memory and ultimately WRITE_FAILED.
  • Wrap promises. The constructor and close()/open() are callback-based; promisify them at the boundary so errors surface as rejections.
  • Test with the mock. The same error classes work against MockBinding. Use disconnectAfter to assert your reconnect path runs.
Gotcha CancelledError is fired on every pending operation when you close() a port. That's normal — your code should ignore CancelledError in any catch block that could see one mid-shutdown.

Edit this page on GitHub