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)#
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.
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:
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#
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) // nullGraceful Error Handling#
Form Validation#
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#
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#
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#
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#
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#
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.