# Youch: the JavaScript error page that renders a stack trace as a readable document

> Youch is a TypeScript library that parses a JavaScript error and renders it as a styled page in the browser or as formatted ANSI in a terminal, with frame navigation, syntax highlighting and code editor links. This looks at what it does, and at where it belongs in an application.

**poppinss/youch** — Pretty print JavaScript errors on the Web and the Terminal

- Repository: https://github.com/poppinss/youch
- Stars: 1,200 · Forks: 39
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/poppinss-youch

## The problem is that a stack trace is not a document

Youch is an error-parsing library that pretty prints JavaScript errors on a web page or the terminal. The pitch is in the screenshots the readme pairs side by side, an unformatted stack trace against the Youch output, and the claim is that the error presented by Youch is a lot more readable and presentable in comparison to the unformatted stack trace.

That is a smaller problem than it sounds and a more annoying one. A JavaScript stack trace is a list of function names and file paths with line numbers, and on a server side framework it arrives as a wall of monospaced text in the response body or in a terminal. Reading it means mentally reconstructing the call chain, and the frames that matter are interleaved with framework internals. Formatting it as a document, with the error at the top, the frames as collapsible sections, and the source of each frame shown, turns that wall into something a developer can navigate.

The audience is therefore the developer on the other end of a stack trace, and the adoption signal in the readme is the list of frameworks that use it: Nitro, Nuxt, Cloudflare and AdonisJS. Those are the places where a framework needs to decide what an unhandled error looks like to a developer, and Youch is that decision, packaged.

The library is MIT licensed, written in TypeScript, and published to npm as `youch`. The default branch is `4.x`, and the current version in the package manifest is 4.1.1.

## toHTML, and the CSP nonce you cannot skip

The HTML output is self-contained and does not require separate CSS or JavaScript files, which is the property that makes it usable inside an error handler. The example uses Hono, and the documentation says you can replace Hono with any other framework of your choice, which is a good sign for a library whose job is to be embedded.

```ts
import { Hono } from 'hono'
import { Youch } from 'youch'

const app = new Hono()
const IN_DEV = process.env.NODE_ENV === 'development'

app.onError(async (error, c) => {
  if (IN_DEV) {
    const youch = new Youch()
    const html = await youch.toHTML(error)
    return c.html(html)
  }
  return c.text(error.message)
})
```

The `toHTML` method takes the error as the first argument and an options object as the second:

```ts
await youch.toHTML(error, {
  title: 'An error occurred',
  cspNonce: '',
  offset: 0,
  ide: 'vscode',
})
```

Four options, and two of them matter more than the others. `title` sets the error page title and defaults to "An error has occurred". `cspNonce` is the one to understand: if your application uses CSP protection, then you must provide the CSP nonce for rendering inline style and script tags, which is a direct consequence of the output being self-contained. A team with a strict policy will have to thread a nonce through the error handler, and that is the integration cost of the design.

`offset` skips a number of frames from the parsed error stack, which is how you hide the framework frames that are always the same. `ide` defines the code editor used when a filename anchor is clicked, and there is a section on configuring code editors and on detecting the user's editor.

## toANSI, because half of the errors never reach a browser

Not every error is a page. A background job, a build script or a CLI prints its failures to a terminal, and that is the case the second method covers.

```ts
try {
  await performSomeAction()
} catch (error) {
  const youch = new Youch()
  const ansiOutput = await youch.toANSI(error)

  console.error(ansiOutput)
}
```

The `toANSI` method takes the same shape, an error and an options object, and the documented option here is `offset` again, for skipping frames at the top of the stack.

The interesting detail is that the two methods share the same underlying model. Youch parses the error first, into a structure it can then render either as a page or as text. That is why the anatomy section describes one error page and its sections rather than two separate outputs, and it is why the options are near-identical: the difference is the renderer, not the parser.

That shared model is also why the library can offer the same niceties in both, the syntax highlighting, the frame navigation, the cause chain, and the metadata block that only makes sense in the HTML output.

## The anatomy of the page, and the parts you can replace

The readme deconstructs the error page section by section, and it is worth following because it shows what the library is actually modelling.

The top-most section displays the Error info, which includes the Error class constructor name, the Error title set using the `options.title` property, and the Error message, highlighted in red. Under it, the Stack trace section displays individual frames as accordion sections, and clicking the section title reveals the frame detail.

Then there is the Raw output, the original unformatted error, which is the escape hatch that makes the page safe to trust, because the formatted view is a rendering of the error and the raw output is the error itself. There is also an Error cause section, which covers the `cause` chain that modern JavaScript errors support and that a naive formatter drops on the floor.

The Metadata section is HTML only, and it carries the extra context the renderer knows about but a plain stack trace does not.

Beyond the anatomy, there are four extension points, and they are the part that makes this usable in a real project. You can use a custom source code loader, which is how the library reads the file content for a frame when the default does not find it. You can inject custom styles, so the page matches your design system rather than looking like a stranger in your app. You can override the syntax highlighter. And you can configure code editors, which is the mechanism behind the `ide` option and the documentation section on detecting the user's code editor.

## Installing, and the beta tag in the instructions

The package is on npm, and the readme gives the three package manager variants.

```sh
npm i youch@beta

# Yarn
yarn add youch@beta

# Pnpm
pnpm add youch@beta
```

Note the tag. The install instructions point at `youch@beta`, while the current published version in the manifest is 4.1.1, and the release history explains why: 4.1.0 was tagged as latest after a stable beta had been tested for more than a year, with 4.1.0-beta.14 before it, whose title is Escape HTML in error context and copy error with complete stack trace.

That release title is the most informative string in the repository for an evaluator. It tells you that a beta cycle was needed to harden the handling of HTML embedded in an error message, and to make copying an error include the complete stack trace. Both of those are exactly the two things you would worry about in a library that renders attacker-influenced strings into an HTML page.

The repository layout is a single package rather than a monorepo, with `index.ts` at the root, `src/` holding the implementation and the templates, `tests/`, `examples/` and `bin/`. The published files are the `build` directory, with the `bin`, `examples` and `tests` subdirectories excluded, and the exports map exposes the main entry, a `./types` entry and a `./templates/*` path, which is how the templates are addressed individually.

## The toolchain, and what the examples are for

The manifest shows a project that treats itself as a library with a real build pipeline rather than a script.

The build is `tsdown` for the bundle plus `tsc --emitDeclarationOnly` for the type declarations, with a `copy:assets` step that copies `src/public/**/*` into the build output, and the `version` and `prepublishOnly` scripts both running a full build so a published artefact is always compiled from source. `release-it` handles the release with conventional changelog commits.

Testing is Japa, the runner from the same author, with the assert, expect, expect-type, file-system and snapshot plugins, and coverage is measured with `c8`. The `pretest` script runs lint first, and the quick test path uses `node --import=@poppinss/ts-exec --enable-source-maps bin/test.ts`, so the test entry point is a TypeScript file executed through a loader rather than compiled ahead of time.

The `examples/` directory is a catalogue of the situations the library is meant for, and the file names are more informative than any description: `axios.ts` for an error thrown inside an HTTP client, `console.ts`, `flydrive.ts` for a file system error, `http_statuses.ts`, `no_trace.ts` for an error with no stack, `pg.ts` for a database driver error, and `web.ts` for the browser case.

That last set is the honest test of an error formatter, because real errors come from third party libraries with their own error shapes, and `no_trace.ts` is the case that breaks naive formatters.

## Where Youch is the wrong tool

Three limits are clear, and they are all about where the output ends up.

The first is that this is a development tool, and the framework examples make that explicit with the `IN_DEV` check that falls back to plain `c.text(error.message)` in production. A rendered error page can contain the source of your application files, your dependency paths and the arguments your functions were called with. Putting that on the public internet because the environment variable was wrong is the kind of mistake this library makes easy.

The second is that a page can only show source it can read, which is why there is a custom source code loader. In a bundled serverless deployment, the file paths in a stack trace often do not exist on disk, so the frames render without their code. That is a deployment-shape limitation, not a bug, and it means the feature that makes Youch worth using is the one most likely to be unavailable in the environment you deploy to.

The third is that a formatted page is not a log. Youch renders one error for one human. A production system wants structured errors, aggregation, sampling and alerting, and a framework that pipes its unhandled exceptions into a logger is solving a different problem.

On maintenance, the picture is fine. v4.1.0-beta.14 was published on 2026-02-12, v4.1.0 on 2026-02-24, v4.1.1 on 2026-03-28, and the last push to the repository was on 2026-06-01. The licence is MIT, with the licence text in `LICENSE.md` at the root, and the repository carries a `SECURITY.md` for reporting problems, which for a library that renders error messages into HTML is the file to read first.

## Conclusion

Youch fits a Node or edge framework team that wants a development error screen people can actually read, with clickable frames that open the right file in the right editor, and it fits a CLI that wants a stack trace with syntax highlighting instead of a wall of paths. It does not fit a production error pipeline, because a page that shows your source code is a development tool, and the library's own recent history, where HTML in the error context had to be escaped, is a reminder of why. Before you wire it in, read the `cspNonce` option and the source loader, because both change what you are allowed to put in the response.

## FAQ

### How do I install Youch?

Install it from npm with `npm i youch@beta`, or `yarn add youch@beta` or `pnpm add youch@beta`. The readme points at the beta tag, and the current published version in the package manifest is 4.1.1, tagged as latest after a stable beta had been tested for more than a year.

### How do I render a JavaScript error as an HTML page?

Create a Youch instance and call `toHTML(error)`, then return the HTML from your framework's error handler. The output is self-contained and needs no separate CSS or JavaScript files, and the second argument accepts `title`, `cspNonce`, `offset` and `ide` options.

### What is the cspNonce option for in Youch?

The HTML output renders inline style and script tags, so if your application uses Content Security Policy protection you must provide the CSP nonce so those inline tags are allowed. The option is called `cspNonce` and is passed with the other options to `toHTML`.

### Can Youch print errors in the terminal?

Yes. The `toANSI(error)` method returns formatted ANSI output for a terminal, with an `offset` option to skip frames at the top of the stack. The example catches an error and writes the result with `console.error`.

### Which frameworks use Youch?

The readme lists Nitro, Nuxt, Cloudflare and AdonisJS as frameworks that use it, which is the adoption signal for a library whose job is to decide what an unhandled error looks like to a developer.

## Sources

- [Issues](https://github.com/poppinss/youch/issues)
- [License: MIT](https://github.com/poppinss/youch/blob/4.x/LICENSE)
- [poppinss/youch on GitHub](https://github.com/poppinss/youch)
- [README](https://github.com/poppinss/youch/blob/4.x/README.md)
- [Releases](https://github.com/poppinss/youch/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/poppinss-youch
