Recipes

Recover From Errors and Failures

Handle typed errors, and react to load failures and stuck tracks.

Hoshimi throws typed errors and emits events for playback failures. Handle both to keep a session resilient.

Typed error handling

Every failure is an instance of a specific error class, so instanceof routes each to the right recovery.

error-handling.ts
import {
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
  ,
} from 'hoshimi';

try {
  // Any Hoshimi operation that may fail
} catch () {
  if ( instanceof ) {
    .('Invalid options:', .);
  } else if ( instanceof ) {
    .('Manager state error:', .);
  } else if ( instanceof ) {
    .('Node connection error:', .);
  } else if ( instanceof ) {
    .('No node available:', .);
  } else if ( instanceof ) {
    .('Queue state error:', .);
  } else if ( instanceof ) {
    .('Playback error:', .);
  } else if ( instanceof ) {
    .('Track resolution failed:', .);
  } else if ( instanceof ) {
    .('Lavalink REST error:', .);
  } else if ( instanceof ) {
    .('Storage adapter error:', .);
  } else {
    .('Unknown error:', );
  }
}

Error categories

Error TypeCauseRecovery
OptionErrorInvalid configurationFix options, restart
ManagerErrorInvalid manager stateCheck manager initialization
NodeErrorNode connection/statusRetry, fallback to another node
PlayerErrorInvalid player operationValidate player state
ResolveErrorTrack lookup failedTry a different search query
RestErrorLavalink HTTP errorRetry with backoff
StorageErrorAdapter operation failedCheck storage backend
NodeManagerErrorNo connected node to pickWait for a node, or add one
QueueErrorQueue holds something that is not a trackInspect what was pushed into it
MergeErrorA required manager option is missingFix the options object

RestError carries the Lavalink response: status, error, path and trace alongside message. NodeError names the node in error.name, so logs point at the right one in a multi-node fleet.

Load failures and stuck tracks

A track can fail to load, or stall mid-playback. Let Hoshimi react automatically with onError, and observe it with the trackStuck event.

stuck-and-errors.ts
const  = ({
  ,
  : [{ : 'localhost', : 2333, : 'youshallnotpass' }],
  : {
    : {
      : true, // stop playback on a track error instead of stalling
    },
  },
});

.('trackStuck', (, ) => {
  .(`Stuck: ${?.. ?? 'unknown'} in ${.}`);
});

onError.autoDestroy tears the player down instead (it takes precedence over autoStop). For disconnects, onDisconnect offers autoReconnect, autoDestroy and autoQueue.

Recovery checklist

  • Before commands: check manager.isUsable() for a quick health gate.
  • Before player operations: verify voice channel access and player existence.
  • Queue operations: guard with queue.isEmpty() before shifting/accessing.
  • Session persistence: save player/queue state after successful updates — see Resume sessions after a restart.
  • Cleanup: on queueEnd and playerDestroy, clear transient storage (lyrics ids, message refs).