# errs

> Simple error creation, boundaries, and formatting utilities

Latest version **1.0.0** (published 2026-02-05) · MIT license · 0 weekly downloads

## Install

```sh
npm install errs
pnpm add errs
yarn add errs
bun add errs
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.0.0 |
| Published | 2026-02-05 |
| First published | 2012-02-24 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=22.0.0 |
| Dependencies | 0 |
| Unpacked size | 35 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 74 |
| Author | Charlie Robbins |
| Maintainers | indexzero |
| Keywords | errors, error, utilities, aggregate-error, error-boundary, error-cause, formatting |

## Links

- npm: https://www.npmjs.com/package/errs
- Repository: https://github.com/indexzero/errs
- Homepage: https://github.com/indexzero/errs#readme
- Issues: https://github.com/indexzero/errs/issues
- npm.io page: https://npm.io/package/errs

## Alternatives

- [@sentry/react-native](https://npm.io/package/@sentry/react-native.md) — 2.6M weekly downloads
- [@ardatan/aggregate-error](https://npm.io/package/@ardatan/aggregate-error.md) — 708.1K weekly downloads
- [custom-error-generator](https://npm.io/package/custom-error-generator.md) — 2.0K weekly downloads
- [@technik-sde/prosemirror-recreate-transform](https://npm.io/package/@technik-sde/prosemirror-recreate-transform.md) — 1.5K weekly downloads
- [@suchipi/error-utils](https://npm.io/package/@suchipi/error-utils.md) — 78 weekly downloads

## Recent versions

- 1.0.0 (latest) — 2026-02-05
- 0.3.2 — 2014-11-26
- 0.3.1 — 2014-11-26
- 0.3.0 — 2014-01-11
- 0.2.4 — 2013-03-07
- 0.2.3 — 2012-08-17
- 0.2.2 — 2012-06-28
- 0.2.0 — 2012-03-03
- 0.1.1 — 2012-02-24

## README

# errs

Simple error creation, boundaries, and formatting utilities for modern Node.js applications.

## Features

- **Simple Error Creation** - Create errors with custom properties in one line
- **Error Boundaries** - Collect errors without immediate throwing
- **Type Guards** - Runtime type checking for errors with TypeScript support
- **Result Pattern** - Rust-style `tryCatch` for exception-free error handling
- **Multi-Format Output** - Format errors for terminal, JSON, or HTML
- **Native Cause Chains** - Built-in support for ES2022 `Error.cause`
- **Error Type Registration** - Register and reuse custom error types
- **Zero Dependencies** - No runtime dependencies

## Installation

```sh
npm install errs
```

## Quick Start

```js
import errs from 'errs'

// Create errors with custom properties
const err = errs.create({
  message: 'User not found',
  status: 404,
  code: 'USER_NOT_FOUND'
})

// Collect multiple errors without throwing
const boundary = errs.boundary()
boundary.add(new Error('Validation failed'))
boundary.add(new Error('Invalid email'))
if (boundary.hasErrors()) {
  boundary.throwIfErrors()
}

// Format errors for different outputs
console.log(errs.format(err, { format: 'terminal' }))
```

## API Reference

### Creating Errors

#### `errs.create(opts)`

Creates a new error with custom properties.

```js
// From a string
const err = errs.create('Something went wrong')

// From an object
const err = errs.create({
  message: 'Database connection failed',
  status: 500,
  code: 'DB_ERROR'
})

// From an array (joined with spaces)
const err = errs.create(['Invalid', 'request', 'parameters'])

// From a function
const err = errs.create(() => ({
  message: 'Dynamic error',
  timestamp: Date.now()
}))
```

#### `errs.create(type, opts)`

Creates an error of a registered type.

```js
class ValidationError extends Error {
  name = 'ValidationError'
}

errs.register('validation', ValidationError)

const err = errs.create('validation', {
  message: 'Invalid input',
  field: 'email'
})
```

### Merging Errors

#### `errs.merge(error, opts)`

Merges an existing error with new properties and sets native cause chain.

```js
try {
  await fetchData()
} catch (original) {
  throw errs.merge(original, {
    message: 'Failed to load user data',
    userId: 123
  })
  // merged.cause === original
}
```

### Error Boundaries

#### `errs.boundary(options)`

Creates an ErrorBoundary for collecting errors without immediate throwing.

```js
const boundary = errs.boundary({
  maxErrors: 100,      // Maximum errors to collect (default: 1000)
  captureStack: true   // Capture creation point (default: true)
})

// Collect errors
try {
  validateEmail(data.email)
} catch (e) {
  boundary.add(e)
}

try {
  validateAge(data.age)
} catch (e) {
  boundary.add(e)
}

// Check and throw if errors exist
if (boundary.hasErrors()) {
  console.log(`Collected ${boundary.count} errors`)
  boundary.throwIfErrors('Validation failed')
}

// Or get as AggregateError
const aggregate = boundary.toAggregateError()

// Clear and reuse
boundary.clear()
```

#### ErrorBoundary Methods

- `add(error)` - Add an error to the boundary
- `hasErrors()` - Check if any errors collected
- `count` - Get number of errors
- `errors` - Get copy of all errors
- `toAggregateError(message)` - Convert to AggregateError
- `throwIfErrors(message)` - Throw if errors exist
- `clear()` - Remove all errors
- `trap(fn)` - Execute sync function, trap errors to boundary
- `trapAsync(fn)` - Execute async function, trap errors to boundary

#### `boundary.trap(fn)` / `boundary.trapAsync(fn)`

Execute functions and automatically collect errors without throwing.

```js
const boundary = errs.boundary()

// Sync operations
const result = boundary.trap(() => JSON.parse(userInput))
if (result.ok) {
  console.log('Parsed:', result.value)
} else {
  console.log('Parse failed, error collected')
}

// Async operations
const fetched = await boundary.trapAsync(() => fetch(url))
if (fetched.ok) {
  const data = await fetched.value.json()
}

// Process multiple and handle all errors at once
items.forEach(item => boundary.trap(() => processItem(item)))
boundary.throwIfErrors('Batch processing failed')
```

### Type Guards

#### `errs.isErrorType(error, ErrorClass)`

Type guard that checks if an error is an instance of a specific class.

```js
try {
  await fetchData()
} catch (err) {
  if (errs.isErrorType(err, TypeError)) {
    // TypeScript knows err is TypeError here
    console.log('Type error occurred')
  }
}
```

#### `errs.isRegisteredType(error, typeName)`

Check if an error matches a registered type name.

```js
errs.register('validation', ValidationError)

if (errs.isRegisteredType(err, 'validation')) {
  // Handle validation error
}
```

#### `errs.assertErrorType(error, ErrorClass, message?)`

Assert error is a specific type, throws TypeError if not.

```js
function handleHttpError(err) {
  // Throws TypeError if err is not HttpError
  const httpErr = errs.assertErrorType(err, HttpError)
  return httpErr.status // TypeScript knows this is HttpError
}
```

### Result Pattern

#### `errs.tryCatch(fn)`

Wraps a sync function to return a Result instead of throwing.

```js
const result = errs.tryCatch(() => JSON.parse(input))
if (result.ok) {
  console.log(result.value)
} else {
  console.log('Parse error:', result.error.message)
}
```

#### `errs.tryCatchAsync(fn)`

Wraps an async function to return a Result instead of throwing.

```js
const result = await errs.tryCatchAsync(() => fetch(url))
if (result.ok) {
  const data = await result.value.json()
} else {
  console.log('Fetch failed:', result.error.message)
}
```

### Parallel Operations

#### `errs.parallel(promises, options)`

Run multiple promises and collect all errors.

```js
const { results, boundary } = await errs.parallel([
  fetchUser(1),
  fetchUser(2),
  fetchUser(3)
])

// Get successful values
const users = results
  .filter(r => r.status === 'fulfilled')
  .map(r => r.value)

// Check for errors
if (boundary.hasErrors()) {
  console.error(`${boundary.count} requests failed`)
}
```

### Error Formatting

#### `errs.format(error, options)`

Format errors for different output targets.

```js
// Terminal output with colors
console.log(errs.format(error, { format: 'terminal', colors: true }))

// JSON for logging
logger.error(errs.format(error, { format: 'json', indent: 2 }))

// HTML for error pages
res.send(errs.format(error, { format: 'html' }))
```

**Terminal Output:**

```
╭─ TypeError: Cannot read property 'x' of undefined
│
│  at processUser (src/users.js:42:15)
│  at async main (src/index.js:10:3)
│
├─ Caused by: NetworkError: Connection refused
│
│  at fetch (src/api.js:23:9)
│
╰─ 2 errors in chain
```

### Error Handling

#### `errs.handle(error, callback, stream)`

Unified error handling for callbacks and EventEmitters.

```js
// With callback
errs.handle(err, (e) => console.error(e))

// With EventEmitter
errs.handle(err, emitter)

// With both
errs.handle(err, callback, emitter)

// Returns emitter if no callback
const emitter = errs.handle(err)
emitter.on('error', handleError)
```

### Type Registration

#### `errs.register(type, ErrorClass)`

Register a custom error type.

```js
class HttpError extends Error {
  name = 'HttpError'
  constructor(message, status) {
    super(message)
    this.status = status
  }
}

errs.register('http', HttpError)

// Use registered type
const err = errs.create('http', {
  message: 'Not found',
  status: 404
})
```

#### `errs.unregister(type)`

Unregister an error type.

```js
errs.unregister('http')
```

### JSON Conversion

#### `errs.toJSON(error)`

Convert error to JSON-serializable object.

```js
const err = new Error('Test error')
err.code = 'TEST_CODE'

const json = errs.toJSON(err)
// { message: 'Test error', stack: '...', code: 'TEST_CODE' }
```

## Named Exports

All functions are available as named exports:

```js
import {
  create,
  boundary,
  format,
  parallel,
  isErrorType,
  isRegisteredType,
  assertErrorType,
  tryCatch,
  tryCatchAsync
} from 'errs'

const err = create('Error message')
const bound = boundary()
const result = tryCatch(() => JSON.parse(data))
```

## Subpath Exports

Import specific modules directly:

```js
import { ErrorBoundary } from 'errs/boundary'
import { format } from 'errs/format'
```

## Use Cases

### Form Validation

```js
const boundary = errs.boundary()

if (!email.includes('@')) {
  boundary.add(new Error('Invalid email'))
}
if (password.length < 8) {
  boundary.add(new Error('Password too short'))
}

boundary.throwIfErrors('Validation failed')
```

### Batch Processing

```js
const boundary = errs.boundary()

for (const item of items) {
  try {
    await processItem(item)
  } catch (err) {
    boundary.add(err)
  }
}

if (boundary.hasErrors()) {
  console.error(`${boundary.count} items failed`)
  await logErrors(boundary.errors)
}
```

### API Error Formatting

```js
app.use((err, req, res, next) => {
  res.status(err.status || 500).send(
    errs.format(err, { format: 'json' })
  )
})
```

## Requirements

- Node.js >= 20.0.0

## Migration from v0.x

See [MIGRATION.md](./MIGRATION.md) for detailed migration guide.

## License

MIT

## Contributors

- [Charlie Robbins](http://github.com/indexzero)
- [Nuno Job](http://github.com/dscape)

---
_Source: https://npm.io/package/errs · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
