Skip to main content
Debug methods are intended for testing only. Do not call injectFault() in production — it will cause the next real submission to return a synthetic failure.

Overview

The sinker.debug object provides access to the fault injection system. Register a fault before enqueueing a transaction to simulate any failure class on demand.
// Register a fee_too_low fault
await sinker.debug.injectFault('fee_too_low');

// Enqueue a real transaction — the next submit will be faulted
const handle = await sinker.enqueue(rawTxBase64);

// The agent retries automatically
const result = await handle.waitFor('finalized');

Methods

debug.injectFault()

Register a one-shot synthetic failure to inject into the next POST /internal/submit call.
const result = await sinker.debug.injectFault(failureClass, rawError?);
failureClass
FaultClass
required
The failure class to inject. One of:
  • 'fee_too_low'
  • 'expired_blockhash'
  • 'bundle_failed'
  • 'compute_exceeded'
  • 'slot_skip'
rawError
string
Optional custom error string stored in the lifecycle entry’s raw_error field. Defaults to "Injected fault: {failureClass} (demo)".
Returns: Promise<FaultInjectResult>
ok
boolean
true when the fault was registered successfully.
next_failure
FaultClass
The failure class that was registered (echoed back for confirmation).
Example — test each failure class:
const faultClasses = [
  'fee_too_low',
  'expired_blockhash',
  'slot_skip',
] as const;

for (const fc of faultClasses) {
  await sinker.debug.injectFault(fc);
  const handle = await sinker.enqueue(rawTxBase64);

  const entries = await handle.lifecycle();
  const faulted = entries.find(e => e.stage === 'failed');
  console.log(fc, '→', faulted?.failure?.type);
}

debug.runFaultDemo()

Register a fault and enqueue a transaction in one call. Returns the fault registration result and the tx handle.
const { faultRegistered, tx_id } = await sinker.debug.runFaultDemo(
  'fee_too_low',
  rawTxBase64,
);

console.log('Fault registered:', faultRegistered);
console.log('Transaction ID:', tx_id);
failureClass
FaultClass
required
The failure class to inject.
txBytes
string
required
Base64-encoded pre-signed transaction bytes.
Returns: Promise<{ faultRegistered: boolean; tx_id: string }>

What the sidecar does on a faulted submit

When a fault is registered and POST /internal/submit is called:
  1. The tx queue is drained normally and bytes are retained for retry
  2. The fault spec is consumed (cleared from next_fault)
  3. A lifecycle entry is written with stage: "failed" and the specified failure_class
  4. TxStatusChanged SSE events are emitted for each tx_id
  5. A BundleSettled SSE event fires with stage: "failed" and failure_type
  6. HTTP 200 is returned with a structured result — no Jito call is made
The agent receives the SSE events and executes its normal retry policy, including fetching raw bytes via GET /tx/raw/:tx_id and re-enqueueing.

Fault coverage

All five failure classes have been validated against the full agent retry cycle on mainnet-beta:
ClassFault injectedAgent retryResult
fee_too_lowEscalate tip to p95✅ PASS
expired_blockhashRe-enqueue (fresh blockhash)✅ PASS
bundle_failedInspect error → retry✅ PASS
compute_exceededHold (instruction broken)✅ PASS
slot_skipRe-enqueue (same tip)✅ PASS