agentleFS
LedgerHQLedgerHQ/ledger-live/.agents/skills/errors/SKILL.md

errors

Skill627 starsChanged 6 days agoMITView on GitHub

How to define and check error classes in Ledger Live. Read when adding a new error, creating an errors.ts file, or checking an error's type.

6 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

3 rules. 0 are common, 0 are distinctive, and 3 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 0

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use the native second argument: super(message, { cause }).

    line 62
  2. Very specific:

    Prefer error.name === "FooNotFound" over instanceof FooNotFound.

    line 80
  3. Very specific:

    Use instanceof only when you are certain the error has not crossed a boundary (e.g.

    line 94

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Errors

Each package owns its errors in its own src/errors.ts, as plain native classes. There is no shared errors lib: the former @ledgerhq/errors package has been removed.

Define errors

A package groups its errors in src/errors.ts. Extend Error directly and set a stable name. The name string is the contract — keep it stable, it is what survives across process/serialization boundaries.

// message-only
export class FooNotFound extends Error {
  override name = "FooNotFound";
}

// with a default message
export class InvalidChallenge extends Error {
  override name = "InvalidChallenge";
  constructor() {
    super("backend returned an invalid challenge");
  }
}

// with extra fields
export class HttpError extends Error {
  override name = "HttpError";
  readonly status: number | undefined;
  constructor(message: string, status?: number) {
    super(message);
    this.status = status;
  }
}

Group a family under a per-package base class so callers can catch the whole set. An excerpt of domain/entity/contact/src/errors.ts, which holds the full family:

export class ContactError extends Error {
  override name: string = "ContactError";
}
export class InvalidContactNameError extends ContactError {
  override name = "InvalidContactNameError" as const;
  constructor() {
    super("Expected letters, spaces, or digits");
  }
}

cause

Use the native second argument: super(message, { cause }). Error cause was standardized in ES2022 and is supported by modern runtimes; its TypeScript typing (ErrorOptions) requires lib: es2022.error (i.e. es2022). Coin modules and some older packages still target es2020 — there, declare and assign manually:

export class BroadcastError extends Error {
  override name = "BroadcastError";
  cause?: unknown;
  constructor(message: string, cause?: unknown) {
    super(message);
    this.cause = cause;
  }
}

Check error type: prefer error.name

Prefer error.name === "FooNotFound" over instanceof FooNotFound.

instanceof breaks once an error crosses a boundary — desktop/mobile IPC, worker messaging, or the external @ledgerhq/coin-module-framework — because the object is rebuilt and loses its prototype. The name string always survives.

// ✅ survives serialization
if (error instanceof Error && error.name === "FooNotFound") { … }

// ⚠️ only works in-process, before any serialization
if (error instanceof FooNotFound) { … }

Use instanceof only when you are certain the error has not crossed a boundary (e.g. caught in the same module that threw it) and you need the typed fields.

Where errors live

  • Logic in one package → that package's src/errors.ts.
  • Used only by an app → that app's errors file, such as apps/ledger-live-desktop/src/errors.ts. Mobile has no app-level errors file yet: add one at the same place the first time it needs one.
  • Shared by several coin modules → libs/ledger-wallet-framework/src/errors.ts (@ledgerhq/ledger-wallet-framework/errors), the shared home below the coin layer.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.