Skip to content

Error Handling

Learn how to handle errors gracefully with rut.ts.

Safe Mode#

Throwing helpers support throwOnError: false to return null instead of throwing errors.

Without Safe Mode (Default)#

TypeScript
import { clean, format, decompose } from 'rut.ts'
 
try {
  clean('invalid')
} catch (error) {
  console.error(error) // Error: Invalid RUT input
}
 
try {
  format('abc')
} catch (error) {
  console.error(error) // Error: Invalid RUT input
}
 
try {
  decompose('123')
} catch (error) {
  console.error(error) // Error: Invalid RUT input
}

Error messages are intentionally generic so invalid RUT values are not echoed into logs or traces.

Catching InvalidRutError#

The throwing helpers (clean, format, getBody, getVerifier, decompose, calculateVerifier, mask) throw an InvalidRutError in their default mode. Detect it with instanceof or its stable code instead of matching the message string — the message is the constant 'Invalid RUT input' and should not be parsed.

TypeScript
import { clean, InvalidRutError } from 'rut.ts'
 
try {
  clean('invalid')
} catch (error) {
  if (error instanceof InvalidRutError) {
    // error.code === 'INVALID_RUT'
    // error.message === 'Invalid RUT input'
    console.error('Rejected invalid RUT input')
  } else {
    throw error
  }
}

If you cannot import the class (for example across module boundaries), check the stable code field instead:

TypeScript
try {
  clean('invalid')
} catch (error) {
  if (error.code === 'INVALID_RUT') {
    console.error('Rejected invalid RUT input')
  } else {
    throw error
  }
}

getInvalidRutError() was removed in 5.0.0 (deprecated since 4.1.0). Catch InvalidRutError (instanceof / .code === 'INVALID_RUT') instead.

With Safe Mode#

TypeScript
import { clean, format, decompose } from 'rut.ts'
 
const cleaned = clean('invalid', { throwOnError: false })
console.log(cleaned) // null
 
const formatted = format('abc', { throwOnError: false })
console.log(formatted) // null
 
const parts = decompose('123', { throwOnError: false })
console.log(parts) // null

Graceful Error Handling#

Form Validation#

TypeScript
import { validate, format, clean } from 'rut.ts'
 
function validateRutInput(input: string) {
  // Quick format check
  const formatted = format(input, {
    incremental: true,
    throwOnError: false,
  })
 
  if (!formatted) {
    return { valid: false, error: 'Invalid format' }
  }
 
  // Full validation
  if (!validate(formatted)) {
    return { valid: false, error: 'Invalid RUT or verifier' }
  }
 
  // Strict validation
  if (!validate(formatted, { strict: true })) {
    return {
      valid: false,
      error: 'Suspicious RUT pattern detected',
    }
  }
 
  // Clean for storage
  const cleaned = clean(formatted)
 
  return {
    valid: true,
    cleaned,
    formatted,
  }
}

API Route Handler#

TypeScript
import { validate, clean } from 'rut.ts'
 
export async function POST(request: Request) {
  const body = await request.json()
 
  // Validate RUT with safe mode
  if (!validate(body.rut)) {
    return Response.json({ error: 'Invalid RUT' }, { status: 400 })
  }
 
  // Clean RUT safely
  const cleaned = clean(body.rut, { throwOnError: false })
  if (!cleaned) {
    return Response.json({ error: 'Cannot process RUT' }, { status: 400 })
  }
 
  // Process...
  return Response.json({ success: true, rut: cleaned })
}

Chain Operations Safely#

TypeScript
import { clean, decompose, calculateVerifier } from 'rut.ts'
 
function processRutSafely(input: string) {
  // Step 1: Clean
  const cleaned = clean(input, { throwOnError: false })
  if (!cleaned) {
    return { error: 'Invalid RUT format', step: 'clean' }
  }
 
  // Step 2: Decompose
  const parts = decompose(cleaned, { throwOnError: false })
  if (!parts) {
    return { error: 'Cannot decompose RUT', step: 'decompose' }
  }
 
  // Step 3: Verify
  const calculated = calculateVerifier(parts.body, { throwOnError: false })
  if (!calculated) {
    return { error: 'Invalid body', step: 'calculate' }
  }
 
  if (calculated !== parts.verifier) {
    return { error: 'Verifier mismatch', step: 'verify' }
  }
 
  return {
    success: true,
    body: parts.body,
    verifier: parts.verifier,
  }
}

Error Messages#

Custom Error Messages#

TypeScript
import { validate, clean } from 'rut.ts'
 
function getRutError(rut: string): string | null {
  if (!rut) return 'RUT is required'
 
  const cleaned = clean(rut, { throwOnError: false })
  if (!cleaned) {
    if (rut.length < 8) return 'RUT too short'
    if (rut.length > 12) return 'RUT too long'
    return 'Invalid RUT format'
  }
 
  if (!validate(cleaned)) {
    return 'Invalid verifier digit'
  }
 
  if (!validate(cleaned, { strict: true })) {
    return 'Suspicious RUT pattern (e.g., 11.111.111-1)'
  }
 
  return null
}
 
// Usage
const error = getRutError(userInput)
if (error) {
  showErrorToUser(error)
}

Localized Errors#

TypeScript
import { validate } from 'rut.ts'
 
const errorMessages = {
  en: {
    required: 'RUT is required',
    invalid: 'Invalid RUT',
    suspicious: 'Suspicious pattern detected',
  },
  es: {
    required: 'El RUT es requerido',
    invalid: 'RUT inválido',
    suspicious: 'Patrón sospechoso detectado',
  },
}
 
function validateWithLocale(rut: string, locale: 'en' | 'es' = 'es') {
  const messages = errorMessages[locale]
 
  if (!rut) return messages.required
  if (!validate(rut)) return messages.invalid
  if (!validate(rut, { strict: true })) return messages.suspicious
 
  return null
}

TypeScript Type Guards#

TypeScript
import { isValidRut } from 'rut.ts'
import type { Rut } from 'rut.ts'
 
// A function that should only ever receive an already-validated RUT:
function chargeInvoice(rut: Rut) {
  // ...the type system guarantees `rut` was validated
}
 
function handleSubmit(input: string) {
  // `isValidRut` is a real type guard — on success it narrows `input` to `Rut`
  if (isValidRut(input)) {
    chargeInvoice(input) // ✅ `input` is now a `Rut`
  } else {
    console.error('Invalid RUT')
  }
}
 
const raw: string = '12.345.678-5'
chargeInvoice(raw) // ❌ compile error — `string` is not assignable to `Rut`
if (isValidRut(raw)) chargeInvoice(raw) // ✅ narrowed to `Rut`

Best Practices#

Always use safe mode (throwOnError: false) when handling user input to avoid unexpected crashes.

In incremental mode, validation will fail for incomplete RUTs. Only validate on blur or submit.

Use strict mode ({ strict: true }) in production to reject placeholder RUTs like 11.111.111-1.