# Error codes

> Every error code Tinka's Commands and HTTP responses return, with when it happens, what returns it and how to fix it.

This guide covers the error codes Tinka returns. You will learn how to:

- Read a Command's error, in a terminal and as JSON
- Look up any code a Command returns, with its cause and its fix
- Look up the codes HTTP clients receive in problem details
- Tell a Command used wrongly from one that failed, by its exit status

## Overview

Every failure Tinka reports carries a **code**: a stable snake_case identifier such as `untrusted_app` or `too_large`. Messages can be reworded between versions, codes don't, so scripts, agents and HTTP clients match on the code. Commands report their codes in the `error` object of their result, and HTTP responses in the `code` member of their problem details.

This page lists the codes Tinka itself returns. Your App's own Commands and handlers add codes of their own, and report them the same way.

## How Commands report errors

In a terminal, a failed Command prints its message on stderr, followed by the hint and the fix when it has them:

```text title="Output"
Error: there is no .env file to write APP_KEY to.
  Fix: Run `cp .env.example .env`, then `act generate:key` again; or run `act generate:key --show` to print the key
```

In [Agent mode](agent-mode.md), the same error is the `error` object of the Command's single JSON result. `error.code` is the code, `error.message` the message, and `error.hint` and `error.fix` appear when the error has them. Some errors add `error.details`, with facts such as the files involved. [Failed runs](agent-mode.md#failed-runs) describes every key.

```text title="Output"
{"command":"generate:key","result":"error","error":{"code":"no_env_file","message":"there is no .env file to write APP_KEY to","fix":"Run `cp .env.example .env`, then `act generate:key` again; or run `act generate:key --show` to print the key"},"duration_ms":0}
```

The exit status tells the two kinds of failure apart. A [usage error](#usage-errors) exits with `2`, an interrupted Command with `130`, or `143` when it was terminated, and every other error with `1`.

## Usage errors

A Command called wrongly fails before it runs, with exit status `2`. Unless the error has a fix of its own, `error.fix` points to the Command's `--help`.

::::options

:::option{name="unknown_command" type="code"}
No Command has that name or alias. When the name looks like a typo, `error.hint` suggests the intended one.
:::

:::option{name="unknown_flag" type="code"}
The Command declares no such flag, or a group was given a flag. `error.hint` suggests a close flag name when there is one.
:::

:::option{name="missing_flag_value" type="code"}
A flag that takes a value was given none, such as `--addr` at the end of the line.
:::

:::option{name="invalid_flag_value" type="code"}
A flag's value doesn't parse, such as `--isolated=yes`, or a prompt refused the value its flag holds. This includes a value read from the flag's environment variable.
:::

:::option{name="missing_argument" type="code"}
A required argument is missing.
:::

:::option{name="missing_flag" type="code"}
The Command needs an answer it would prompt a person for, and no one can answer. `error.fix` names the flag to pass, and the environment variable that can set it, if any.
:::

:::option{name="too_many_arguments" type="code"}
The Command was given more arguments than it takes. The message says how many it takes.
:::

:::option{name="invalid_argument" type="code"}
An argument doesn't parse as the type the Command expects, such as a word where it expects a number.
:::

:::option{name="usage" type="code"}
Any other mistake in how the Command was called, explained in the message. Tinka's Commands return it for a `--module` that isn't a module path, a `--target` that isn't `os/arch`, a name a generator can't use, a stub `act publish:stubs` doesn't know, and `act test --watch` in Agent mode.
:::

:::option{name="confirmation_required" type="code"}
A destructive Command runs while `APP_ENV` is `production`, or any value other than `development` or `test`, and no one can confirm it. Pass `--force` to run it. See [Guarded Commands](agent-mode.md#guarded-commands).
:::

:::option{name="prohibited" type="code"}
The App prohibits the Command. `--force` doesn't run it either, so don't retry.
:::

::::

## Errors any Command can return

These come from the machinery every Command shares, so any Command can return them, including your App's own.

::::options

:::option{name="interrupted" type="code"}
The Command was stopped by a signal, such as Ctrl+C or `kill`, or a person cancelled a prompt with Ctrl+C or Ctrl+D. Exits with `130`, or `143` for `SIGTERM`.
:::

:::option{name="cancelled" type="code"}
A person answered no when a destructive Command asked for confirmation in production.
:::

:::option{name="isolation_failed" type="code"}
An `--isolated` run couldn't take its lock. `error.hint` holds the reason; check that your user cache directory exists and is writable.
:::

:::option{name="exec_failed" type="code"}
A program the Command ran with `c.Exec` exited with a non-zero status, or couldn't start. The message names the program and its status, and its output is in the Command's output, or in `log` and `tail` for an agent.
:::

:::option{name="error" type="code"}
The Command returned a plain Go error, without a code of its own. The message is the error's text.
:::

:::option{name="unexpected_prompt" type="code"}
Only in tests run with `clitest`: the Command asked a prompt the test has no answer for. Answer it with `Answer(name, value)` on the runner.
:::

:::option{name="invalid_answer" type="code"}
Only in tests run with `clitest`: the prompt refused the test's answer. A person would be asked again, which a test can't be, so give an answer the prompt accepts.
:::

::::

## act

These come from `act`'s own Commands and from `act` deciding whether it may run the App's code. See [Commands](commands.md).

::::options

:::option{name="not_an_app" type="code"}
`act serve`, `act build`, `act test`, `act trust` or a generator ran outside an App. An App is a module whose `go.mod` requires Tinka, with its main package beside it, owned by you and not writable by others. Run the Command from the App's directory.
:::

:::option{name="untrusted_app" type="code"}
`act` would build and run the App's code, and the App isn't trusted: no one could answer the question, or the person answered no. It comes from `act serve`, `act test` and any of the App's own Commands. If you trust the code, run `act trust` in the App's directory, or pass `--trust` to `act serve` or `act test`, then run the Command again. See [act trust](commands.md#act-trust).
:::

:::option{name="trust_failed" type="code"}
The trust list in your user config directory couldn't be written, or other users can change it. `error.hint` says which.
:::

:::option{name="build_failed" type="code"}
The App didn't compile. From `act build`, the compiler's errors are in the output. From `act test`, `error.details.build_errors` holds them for each package. When `act` builds the App to run one of its Commands, `error.hint` holds them. Fix the errors, then run the Command again.
:::

:::option{name="tests_failed" type="code"}
`act test` ran, and tests failed. `error.details` holds the counts, and `error.details.failures` lists each failed test with the last lines it printed. Run `act test --failed` to run only them again.
:::

:::option{name="no_env_file" type="code"}
`act generate:key` found no `.env` file to write the key to, and it never creates one. Copy `.env.example` to `.env` and run it again, or pass `--show` to print the key.
:::

:::option{name="invalid_app_env" type="code"}
`act generate:key` can't tell where the key belongs, because `APP_ENV` isn't `development`, `test` or `production`. Fix `APP_ENV`.
:::

::::

## act serve

`act serve` returns these when it can't take the address it serves on. A build error while it runs is not an error code: the old App keeps serving, and the errors appear in the terminal and in the browser.

::::options

:::option{name="addr_in_use" type="code"}
Another program listens on `--addr`, such as another `act serve` or the App started on its own. Stop it, or pass another port, such as `--addr localhost:3001`.
:::

:::option{name="listen_failed" type="code"}
`--addr` can't be listened on, such as the address of another machine. `error.hint` holds the reason.
:::

::::

The dev server's own HTTP answers are plain text for API clients, or its error page for browsers, without a code: `403` for a host name it doesn't answer for (see `--allow-host`), `502` while the App is down or its build failed, and `503` when the App is still starting after a minute.

## Generators

The `act make:` generators and `act publish:stubs` return these. A name a generator can't use is the [usage error](#usage-errors) `usage`. See [Scaffolding](../guides/concepts/scaffolding.md).

::::options

:::option{name="file_exists" type="code"}
A file the generator would create exists, and nothing was written. `error.details` lists the files. Pass `--force` to replace them, or choose another name.
:::

:::option{name="codemod_manual" type="code"}
The files were created, but a registration, such as the route in `start/routes.go`, couldn't be placed. `error.fix` holds the line to add and where, and `error.details.manual` the same as data. See [Register by hand](../guides/concepts/scaffolding.md#register-by-hand).
:::

:::option{name="stub_invalid" type="code"}
One of the App's stubs in `stubs/` uses a placeholder that doesn't exist, or renders Go that doesn't parse. Fix the stub, or delete it to use the default.
:::

::::

## Forwarding

The Tinka CLI and `act` build the program they forward to, such as the App's binary, into your user cache directory. These codes come from that build's cache. See [Where act keeps its files](environment-variables.md#where-act-keeps-its-files).

::::options

:::option{name="no_cache_dir" type="code"}
Go can't find your user cache directory. Set `HOME`, or `XDG_CACHE_HOME`, and run the Command again.
:::

:::option{name="unsafe_cache_dir" type="code"}
The build cache directory is readable or writable by other users, so a binary in it can't be trusted. `error.fix` names the directory: run `chmod 700` on it, or remove it.
:::

::::

A build that fails is `build_failed`, described under [act](#act).

## tinka new

`tinka new` returns these while it creates an App. See [tinka new](commands.md#tinka-new).

::::options

:::option{name="dir_not_empty" type="code"}
The directory exists and holds files. Nothing was changed. `error.details.dir` holds the directory; choose another, or empty this one.
:::

:::option{name="kit_failed" type="code"}
The Starter kit couldn't be copied into the directory. `error.hint` holds the reason, and the directory is removed.
:::

:::option{name="install_failed" type="code"}
The App was created, but its dependencies didn't download. `error.hint` holds the go command's output. Run `go mod tidy` in the App's directory once Go can reach Tinka; during the alpha, check `GOPRIVATE`, as [Installation](../installation.md) explains.
:::

::::

## The App's Commands

Every App's binary runs Tinka's built-in Commands, such as `about`, and the App's own Commands, which `act` forwards to it.

::::options

:::option{name="app_start_failed" type="code"}
One of the App's own Commands couldn't run, because the App failed to start: a provider's `Boot`, `Start` or `Ready` hook returned an error. `error.hint` holds it, and whatever had started is shut down.
:::

:::option{name="app_boot_failed" type="code"}
`act about` couldn't boot the App, because a provider failed to boot. `error.hint` holds its error.
:::

::::

## Contributor Commands

These come from the Commands contributors run inside the Tinka repo, which the Tinka CLI forwards to its tooling.

::::options

:::option{name="not_in_repo" type="code"}
`tinka verify` or a `tinka docs` Command ran outside a Tinka checkout, where Go finds no `go.work` file. The message and the fix name the Command that ran. Run it from your checkout.
:::

:::option{name="check_failed" type="code"}
One of `tinka verify`'s checks failed. The message names it, and `error.fix` says how to fix it, such as `gofmt -w .`.
:::

:::option{name="docs_invalid" type="code"}
`tinka docs build` couldn't build the docs, such as for a broken link. `error.hint` holds every problem.
:::

:::option{name="render_failed" type="code"}
`tinka docs sample` couldn't render the sample page. `error.hint` holds the reason.
:::

::::

## HTTP errors

A Handler that returns a `*tinka.Error`, and every failure Tinka detects on its own, become RFC 9457 problem details with `Content-Type: application/problem+json`, or a small HTML page for a browser. `title` is the status's standard text, and the problem has no `type` member, so match on `code`:

```json title="Response"
{
  "title": "Request Entity Too Large",
  "status": 413,
  "detail": "The request body is larger than 1 MiB.",
  "code": "too_large",
  "request_id": "S5QWQ3DAEXTVZ6M7F4DZEL6EBI"
}
```

`hint` says what to do about the error, `fields` maps each invalid field to its problem, and `debug` holds a server error's cause when `Debug` is on. See [Read the response clients get](../guides/basics/exception-handling.md#read-the-response-clients-get). Your Handlers can return any code of their own, such as `email_taken`.

::::options

:::option{name="bad_request" type="400"}
Returned by `tinka.BadRequest`. Tinka returns it for an empty JSON body, and for a body that couldn't be read.
:::

:::option{name="bad_json" type="400"}
The body isn't valid JSON, ends in the middle of a value, or couldn't be decoded. The detail gives the byte offset of a syntax error.
:::

:::option{name="bad_form" type="400"}
An `application/x-www-form-urlencoded` body isn't a valid form.
:::

:::option{name="bad_multipart" type="400"}
A multipart body has no boundary, is malformed, or was cut short. Let the HTTP client set the `Content-Type` of a multipart body.
:::

:::option{name="bad_encoding" type="400"}
The body isn't compressed the way its `Content-Encoding` says.
:::

:::option{name="unauthorized" type="401"}
Returned by `tinka.Unauthorized`: the request needs valid credentials.
:::

:::option{name="forbidden" type="403"}
Returned by `tinka.Forbidden`: the credentials are valid, but not allowed this.
:::

:::option{name="cross_origin" type="403"}
A browser request that changes data (`POST`, `PUT`, `PATCH`, `DELETE`) came from another origin, and was refused before any middleware ran. Send it from the App's own origin.
:::

:::option{name="not_found" type="404"}
No route matches the path, a file sent with `tinka.SendFile` or `tinka.Download` doesn't exist, or a Handler returned `tinka.NotFound`.
:::

:::option{name="method_not_allowed" type="405"}
The path has routes, but none for this method. The `Allow` header and `hint` list the methods it takes.
:::

:::option{name="body_timeout" type="408"}
The body took longer than 30s to arrive.
:::

:::option{name="conflict" type="409"}
Returned by `tinka.Conflict`: the request clashes with the current state, such as an email address that already has an account.
:::

:::option{name="too_large" type="413"}
The body is larger than `HTTPConfig.MaxBodyBytes`, or `MaxUploadBytes` for multipart, or a form has too many fields. Raise the limit for the App, or for some routes with `tinka.BodyLimit`. See [Change the size limits](../guides/basics/body-parser.md#change-the-size-limits).
:::

:::option{name="unsupported_media_type" type="415"}
`c.Body` received a `Content-Type` other than JSON, a form or a multipart form. `hint` lists the types it takes.
:::

:::option{name="unsupported_charset" type="415"}
The body's `charset` isn't UTF-8.
:::

:::option{name="unsupported_encoding" type="415"}
The body's `Content-Encoding` isn't `gzip`, `x-gzip`, `deflate` or `identity`. Send it uncompressed, or compressed with gzip or deflate.
:::

:::option{name="invalid" type="422"}
Some fields are invalid: a value doesn't fit its field's type, the type's `Valid` method found problems, or a Handler returned `tinka.Invalid`. `fields` lists every invalid field at once, such as `items.0.qty`.
:::

:::option{name="internal" type="500"}
Any error that isn't a `*tinka.Error`, a panic, or a `*tinka.Error` whose status isn't between 400 and 599. The client learns nothing more; the log has the cause, and so does `debug` when `Debug` is on.
:::

:::option{name="timeout" type="503"}
The request's deadline, such as one set by `tinka.Timeout`, ran out before the Handler answered. `hint` tells the client to try again in a moment.
:::

::::

See also: [Agent mode](agent-mode.md), [Commands](commands.md), [Exception handling](../guides/basics/exception-handling.md), [Body parser](../guides/basics/body-parser.md), [Environment variables](environment-variables.md)
