When handling failures, classify them as recoverable vs unrecoverable, then apply a consistent rule: log with enough context, continue only for recoverable side-effects, and fail fast with explicit (prefer custom) errors for invalid/unknown inputs or internal invariants.

Apply it like this:

Example pattern (recoverable side-effect):

try {
  registerDiagramIconPacks(config.icons);
} catch (error) {
  log.error(
    'Failed to register icon packs, continuing with diagram render:',
    error,
  );
  // continue rendering
}

Example pattern (unrecoverable invalid input):

class InvalidStyleError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'InvalidStyleError';
  }
}

function parseRadius(value: string): number {
  if (!/^\d+$/.test(value)) {
    throw new InvalidStyleError(`radius value '${value}' must be a number`);
  }
  return parseInt(value, 10);
}

Example pattern (consistent propagation with suppression):

try {
  await diag.renderer.draw(text, id, version, diag);
} catch (e) {
  if (config.suppressErrorRendering) {
    removeTempElements();
  } else {
    errorRenderer.draw(text, id, version);
  }
  throw e;
}