---
title: "Help, version, and errors"
description: "Print help and version output, describe routes and parameters, and report parse failures"
canonical: https://bomb.sh/docs/router/guides/help-version-and-errors/
---

# Help, version, and errors

`parse()` never prints and never exits. It returns an intent or a failure, and three helpers turn that result into text:

* `printHelp()` renders help for a help intent.
* `printVersion()` renders the version for a version intent.
* `printErrors()` renders every issue in a failure.

Each helper returns a string. Your application decides where to print it and which exit code to use.

## Print help and version

Switch on `method` and pass the intent to its helper:

```ts
import process from "node:process";
import {
  command,
  description,
  name,
  parse,
  printErrors,
  printHelp,
  printVersion,
  route,
  version,
} from "@bomb.sh/router";

const app = command(
  name("gh"),
  description("Work seamlessly with GitHub from the command line."),
  version("2.62.0"),
  route(
    name("pr"),
    description("Manage pull requests"),
    command(
      name("list"),
      description("List pull requests in a repository"),
    ),
  ),
);

const result = parse(app, { argv: process.argv.slice(2) });

if (!result.ok) {
  console.error(printErrors(result));
  process.exit(1);
}

if (result.method === "help") console.log(printHelp(result));
if (result.method === "version") console.log(printVersion(result));
```

`gh --version` prints:

```text
gh 2.62.0
```

## Describe routes and parameters

`description()` adds text to help. It works on `command()`, `route()`, `option()`, `toggle()`, and `argument()`. After adding described `repo`, `browse`, and `copilot` routes to the app above, `gh --help` prints:

```text
gh 2.62.0
Work seamlessly with GitHub from the command line.

Usage:
  gh [OPTIONS] [COMMAND]

Commands:
  pr       Manage pull requests
  repo     Manage repositories
  browse   Open the repository in the browser
  copilot  Ask Copilot for help

Options:
  -h, --help     Print help
  -v, --version  Print version
```

Help for a child route lists its own options. For a `pr list` command with described `--state` and `--limit` options and an undescribed `--repo` option, `gh pr list --help` prints:

```text
pr list
List pull requests in a repository

Usage:
  pr list [OPTIONS]

Options:
  --repo, -R <VALUE>
  --state <VALUE>      Filter by state
  --limit, -L <VALUE>  Maximum number of pull requests to fetch
  -h, --help           Print help
```

Positional arguments get their own section. For a `repo clone` command with a described `repository` argument, `gh repo clone --help` prints:

```text
repo clone
Clone a repository locally

Usage:
  repo clone [OPTIONS] <REPOSITORY>

Arguments:
  <REPOSITORY>  Repository to clone

Options:
  -h, --help  Print help
```

Help shows every option value as `<VALUE>` and does not show schema defaults. If users need to know a default or a format, put it in the description.

## Report failures

A failure has one of two codes:

* `method-not-allowed` means the route does not support the requested method. See [Routes and methods](/docs/router/guides/routes-and-methods/#handle-unsupported-methods).
* `unprocessable-content` means the input could not become a valid model.

`printErrors()` prints one line per issue. Unexpected input comes first, then schema issues prefixed with the parameter name. `gh pr list --state draft --limit lots bogus` prints:

```text
unexpected: `bogus`
state: Invalid option: expected one of "open"|"closed"|"merged"|"all"
limit: Invalid input: expected number, received string
```

The router reports every issue it finds, not only the first one, so the user can fix them all at once.

## Format errors yourself

To format failures your own way, narrow on `code`. An `unprocessable-content` failure has an `issues` list of [Standard Schema](https://standardschema.dev/) issues, each with a `message` and an optional `path`. A `method-not-allowed` failure has the requested `method` and the `allowed` methods instead:

```ts
import process from "node:process";
import { command, name, parse } from "@bomb.sh/router";

const app = command(name("gh"));

const result = parse(app, { argv: process.argv.slice(2) });

if (!result.ok && result.code === "unprocessable-content") {
  for (const issue of result.issues) {
    const key = issue.path
      ?.map((p) => (typeof p === "object" ? p.key : p))
      .join(".");
    console.error(key ? `${key}: ${issue.message}` : issue.message);
  }
  process.exit(1);
}
```
