Skip to content

Error Handling

RANDSUM uses a never-throw design. The roll() function never raises an exception — errors are returned as values in the result object.

When roll() encounters an error, it returns an object where result.error is set and result.total is 0. Check for result.error before using result.total:

import { roll } from '@randsum/roller'
const result = roll(userInput)
if (result.error) {
// result.total is 0 — do not use it
console.error(result.error.message)
return
}
// TypeScript narrows the type here — result.total is number
console.log(result.total)

roll() returns an error when:

  • The notation string is syntactically invalid ('4dX', 'not dice')
  • The options object has invalid values (e.g., sides: 0, quantity: -1)
  • A modifier receives an out-of-range argument

Valid-but-unusual inputs (like roll(1) for a single-sided die) are not errors.

If you want to check notation before passing it to roll(), use validateNotation() or the isDiceNotation() type guard:

import { isDiceNotation, roll } from '@randsum/roller'
function rollUserInput(input: string) {
if (!isDiceNotation(input)) {
return { error: 'Not valid dice notation' }
}
// input is now typed as DiceNotation
return roll(input)
}
import { validateNotation } from '@randsum/roller'
const validation = validateNotation('4d6L')
if (!validation.valid) {
console.error(validation.error.message)
} else {
// validation.options contains the structured roll options
console.log(validation.options)
}

result.error is typed as RandsumError | null. On success it is null; on error it is a RandsumError. result.total is always a number — on error its value is 0.

import { roll } from '@randsum/roller'
const result = roll('2d6')
if (result.error !== null) {
// result.error is RandsumError — inspect result.error.message
// result.total is 0 — do not use it for game logic
return
}
// result.error is null — safe to use result.total
console.log(result.total)
  • Always check result.error when rolling user-provided input (form fields, chat commands, API parameters)
  • Internal rolls with hardcoded notation can skip the check — roll('2d6') will never produce an error
  • Use isDiceNotation() to validate strings at system boundaries (user input, external APIs)