usertrust
API Reference

Errors

Seven domain error classes with structured hints and documentation URLs.

usertrust defines seven domain-specific error classes. All extend Error and include structured hint and docsUrl properties for actionable diagnostics.

Catching Errors

import {
  InsufficientBalanceError,
  PolicyDeniedError,
  LedgerUnavailableError,
} from "usertrust";

try {
  const { response, receipt } = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello" }],
  });
} catch (err) {
  if (err instanceof InsufficientBalanceError) {
    console.log(`Need ${err.required} UT, have ${err.available} UT`);
    console.log(err.hint);
  }
  if (err instanceof PolicyDeniedError) {
    console.log(`Blocked: ${err.reason}`);
  }
  if (err instanceof LedgerUnavailableError) {
    console.log(`TigerBeetle down: ${err.cause_message}`);
  }
}

Every error class follows the same pattern: a descriptive message, a hint with a suggested fix, and a docsUrl pointing to detailed documentation.


InsufficientBalanceError

Thrown when the requested LLM call would exceed the remaining budget.

class InsufficientBalanceError extends Error {
  readonly userId: string;
  readonly required: number;    // usertokens needed
  readonly available: number;   // usertokens remaining
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: During the PENDING hold phase, before the LLM call is forwarded to the provider. No tokens are consumed.

Hint: "Increase the budget in trust() options or add funds via the ledger."


PolicyDeniedError

Thrown when a policy rule or PII detector blocks the request.

class PolicyDeniedError extends Error {
  readonly reason: string;
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: During policy evaluation, before the LLM call. The reason field describes which rule or PII type triggered the denial.

Hint: 'Check your policy rules in .usertrust/policies/ or use { pii: "warn" } to downgrade PII enforcement.'


AccountNotFoundError

Thrown when the TigerBeetle account for the given user does not exist.

class AccountNotFoundError extends Error {
  readonly userId: string;
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: During ledger initialization or the first spend attempt.

Hint: 'Run "npx usertrust init" to create accounts, or verify the userId matches your config.'


IdempotencyConflictError

Thrown when a transfer with the same ID has already been submitted to TigerBeetle.

class IdempotencyConflictError extends Error {
  readonly key: string;
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: During the PENDING hold phase, if the generated transferId collides with an existing transfer.

Hint: "This transfer was already submitted. Use a unique transferId for retries."


LedgerUnavailableError

Thrown when TigerBeetle is unreachable. The LLM call is not forwarded to the provider.

class LedgerUnavailableError extends Error {
  readonly cause_message: string;
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: Before any LLM call, during the connection check or PENDING hold attempt. This is failure mode 15.4 -- no tokens are at risk because no hold was placed.

Hint: 'Start TigerBeetle with "npx usertrust tb start" or use { dryRun: true } to skip the ledger.'

When TigerBeetle is unreachable, usertrust refuses to forward the request. This is by design -- without a ledger, budget enforcement is impossible.


AuditDegradedError

Thrown (or flagged) when the audit chain write fails after the LLM call and ledger settlement both succeed.

class AuditDegradedError extends Error {
  readonly cause_message: string;
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: After the LLM call succeeds and the ledger POST settles. This is failure mode 15.3. The response is still returned to the caller with auditDegraded: true on the receipt. The failed event is written to the dead-letter queue.

Hint: "Check disk space and permissions on the .usertrust/audit/ directory."

usertrust never fails the user on audit degradation. If the LLM call succeeded and the ledger settled, the response is always returned.


VaultNotInitializedError

Thrown when the .usertrust/ vault directory does not exist.

class VaultNotInitializedError extends Error {
  readonly path: string;
  readonly hint: string;
  readonly docsUrl: string;
}

When it fires: During trust() initialization, before any LLM calls.

Hint: 'Run "npx usertrust init" to create the vault directory.'


Error Summary

ErrorFailure ModeLLM Call Forwarded?Tokens At Risk?
InsufficientBalanceErrorPre-callNoNo
PolicyDeniedErrorPre-callNoNo
AccountNotFoundErrorPre-callNoNo
IdempotencyConflictErrorPre-callNoNo
LedgerUnavailableError15.4NoNo
AuditDegradedError15.3Yes (succeeded)No (settled)
VaultNotInitializedErrorPre-callNoNo

All pre-call errors are thrown before any interaction with the LLM provider. No tokens are consumed and no budget is affected.