Skip to main content

Errors

All uniku ID generators export standardized error classes for consistent error handling across different ID types.

Import

// Import from specific generator
import { InvalidInputError, BufferError, ParseError, UniqueIdError } from 'uniku/uuid/v4'
import { InvalidInputError, ParseError, UniqueIdError } from 'uniku/cuid2'
import { InvalidInputError, UniqueIdError } from 'uniku/nanoid'

Error Hierarchy

All errors extend the base UniqueIdError class:
UniqueIdError (abstract base class)
β”œβ”€β”€ InvalidInputError
β”œβ”€β”€ ParseError
└── BufferError

Base Error: UniqueIdError

Abstract base class for all uniku errors. Provides structured error information compatible with Effect’s catchTag pattern.

Properties

_tag
string
required
Discriminated union tag for pattern matching (e.g., "InvalidInputError", "ParseError", "BufferError")
code
string
required
Machine-readable error code (e.g., "UUID_RANDOM_BYTES_TOO_SHORT", "NANOID_ALPHABET_TOO_SHORT")
message
string
required
Human-readable error message
name
string
required
Error class name (e.g., "InvalidInputError")

Type Definition

export abstract class UniqueIdError extends Error {
  abstract readonly _tag: string
  abstract readonly code: string

  constructor(message: string) {
    super(message)
    this.name = this.constructor.name
  }
}

InvalidInputError

Thrown when generator arguments are invalid (bad size, alphabet, length, timestamp, version).

Properties

_tag
'InvalidInputError'
required
Always "InvalidInputError" for type discrimination
code
string
required
Specific error code indicating what input was invalid

Type Definition

export class InvalidInputError extends UniqueIdError {
  readonly _tag = 'InvalidInputError' as const

  constructor(
    readonly code: string,
    message: string,
  ) {
    super(message)
  }
}

Common Error Codes

UUID v4 / UUID v7

// Thrown when random bytes array is too short (< 16 bytes)
const shortBytes = new Uint8Array(10)
try {
  uuidv4({ random: shortBytes })
} catch (error) {
  console.log(error.code) // => "UUID_RANDOM_BYTES_TOO_SHORT"
  console.log(error.message) // => "Random bytes length must be >= 16"
}

ULID

// Thrown when random bytes array is too short (< 10 bytes)
const shortBytes = new Uint8Array(5)
try {
  ulid({ random: shortBytes })
} catch (error) {
  console.log(error.code) // => "ULID_RANDOM_BYTES_TOO_SHORT"
  console.log(error.message) // => "Random bytes length must be >= 10 for ULID"
}

CUID2

// Thrown when length is not between 2 and 32
try {
  cuid2({ length: 50 })
} catch (error) {
  console.log(error.code) // => "CUID2_LENGTH_OUT_OF_RANGE"
  console.log(error.message) // => "CUID2 length must be between 2 and 32. Received: 50"
}

Nanoid

// Thrown when size is not a non-negative integer
try {
  nanoid(-5)
} catch (error) {
  console.log(error.code) // => "NANOID_SIZE_INVALID"
  console.log(error.message) // => "Size must be a non-negative integer"
}

KSUID

// Thrown when random bytes array is too short (< 16 bytes)
try {
  ksuid({ random: new Uint8Array(10) })
} catch (error) {
  console.log(error.code) // => "KSUID_RANDOM_BYTES_TOO_SHORT"
  console.log(error.message) // => "Random bytes length must be >= 16 for KSUID"
}

ParseError

Thrown when parsing/decoding an ID string that has invalid format or characters.

Properties

_tag
'ParseError'
required
Always "ParseError" for type discrimination
code
string
required
Specific error code indicating what parsing failed

Type Definition

export class ParseError extends UniqueIdError {
  readonly _tag = 'ParseError' as const

  constructor(
    readonly code: string,
    message: string,
  ) {
    super(message)
  }
}

When It’s Thrown

import { uuidv4, ParseError } from 'uniku/uuid/v4'

try {
  const bytes = uuidv4.toBytes("invalid-uuid-string")
} catch (error) {
  if (error instanceof ParseError) {
    console.log('Invalid UUID format')
  }
}

BufferError

Thrown when a byte array or buffer is too short or an offset is out of bounds.

Properties

_tag
'BufferError'
required
Always "BufferError" for type discrimination
code
string
required
Specific error code indicating what buffer operation failed

Type Definition

export class BufferError extends UniqueIdError {
  readonly _tag = 'BufferError' as const

  constructor(
    readonly code: string,
    message: string,
  ) {
    super(message)
  }
}

Common Error Codes

// Thrown when buffer offset + 16 bytes exceeds buffer length
import { uuidv4, BufferError } from 'uniku/uuid/v4'

const buffer = new Uint8Array(10) // Too small

try {
  uuidv4(undefined, buffer, 0) // Needs 16 bytes
} catch (error) {
  if (error instanceof BufferError) {
    console.log(error.code) // => "UUID_BUFFER_OUT_OF_BOUNDS"
    console.log(error.message) // => "UUID byte range 0:15 is out of buffer bounds"
  }
}

Error Handling Patterns

Type Guards

import { uuidv4, InvalidInputError, BufferError, ParseError } from 'uniku/uuid/v4'

try {
  const id = uuidv4({ random: new Uint8Array(10) })
} catch (error) {
  if (error instanceof InvalidInputError) {
    console.log('Invalid input:', error.code)
  } else if (error instanceof BufferError) {
    console.log('Buffer error:', error.code)
  } else if (error instanceof ParseError) {
    console.log('Parse error:', error.code)
  } else {
    throw error // Re-throw unknown errors
  }
}

Effect-style Pattern Matching

The _tag property enables discriminated union pattern matching:
import { uuidv4, UniqueIdError } from 'uniku/uuid/v4'

try {
  const id = uuidv4({ random: new Uint8Array(10) })
} catch (error) {
  if (error instanceof UniqueIdError) {
    switch (error._tag) {
      case 'InvalidInputError':
        console.log('Invalid input:', error.code)
        break
      case 'BufferError':
        console.log('Buffer error:', error.code)
        break
      case 'ParseError':
        console.log('Parse error:', error.code)
        break
    }
  }
}

Code-based Handling

import { nanoid, InvalidInputError } from 'uniku/nanoid'

try {
  const id = nanoid({ alphabet: 'a' })
} catch (error) {
  if (error instanceof InvalidInputError) {
    switch (error.code) {
      case 'NANOID_ALPHABET_TOO_SHORT':
        console.log('Alphabet must have at least 2 characters')
        break
      case 'NANOID_ALPHABET_DUPLICATE':
        console.log('Alphabet contains duplicate characters')
        break
      case 'NANOID_SIZE_TOO_LARGE':
        console.log('Size exceeds maximum allowed')
        break
      default:
        console.log('Unknown error:', error.message)
    }
  }
}

Validation Before Generation

Prevent errors by validating inputs:
import { nanoid } from 'uniku/nanoid'

function generateSafeNanoid(size: number, alphabet?: string): string {
  // Validate size
  if (!Number.isInteger(size) || size < 0) {
    throw new Error('Size must be a non-negative integer')
  }
  if (size > 2048) {
    throw new Error('Size must not exceed 2048')
  }

  // Validate alphabet
  if (alphabet !== undefined) {
    if (alphabet.length < 2) {
      throw new Error('Alphabet must contain at least 2 characters')
    }
    if (new Set(alphabet).size !== alphabet.length) {
      throw new Error('Alphabet contains duplicate characters')
    }
  }

  return nanoid({ size, alphabet })
}

See Also

Build docs developers (and LLMs) love