---
title: Error codes
description: What a failure carries, and where each code comes from.
---

## 1. Why they are append-only

Append-only. Once shipped, a code's meaning never changes and a code is never
removed; new conditions get new codes. Agents branch on `code`, never on the
human `error` string, which changes freely as wording improves.

## 2. The codes

The sources ship the codes as a bare list, and no sentence in them states what any one code means. So the columns below are the ones the sources do state: the typed domain failures the CLI translates into each code, the suggestions it offers for those failures, and every file that names the code. A row with an empty second and fourth column is a code the sources name only in the vocabulary list.

| Code | From these failures | Suggestions | Named in |
| --- | --- | --- | --- |
| `ERR_UNKNOWN_COMMAND` | - | *none* | `apps/cli/src/help.ts`, `apps/cli/src/run.ts` |
| `ERR_MISSING_ARGUMENT` | - | *none* | `apps/cli/src/apply.ts`, `apps/cli/src/help.ts`, `apps/cli/src/run.ts` |
| `ERR_INVALID_FLAG` | - | *none* | `apps/cli/src/apply.ts`, `apps/cli/src/help.ts`, `apps/cli/src/integrations.ts`, `apps/cli/src/run.ts` |
| `ERR_UNEXPECTED_ARGUMENT` | - | *none* | `apps/cli/src/help.ts`, `apps/cli/src/run.ts` |
| `ERR_REPO_REQUIRED` | - | *none* | `apps/cli/src/help.ts`, `apps/cli/src/run.ts` |
| `ERR_PATH_NOT_FOUND` | `PathNotFound` | `memhtml resolve <the path you cited> — a correction or an eviction may have moved it`, `memhtml search <what you were looking for>`, `memhtml list` | `apps/cli/src/apply.ts`, `apps/cli/src/errors.ts`, `apps/cli/src/exec.ts`, `apps/mcp/src/failure.ts`, `apps/mcp/src/resources.ts` |
| `ERR_INVALID_MEMORY` | `InvalidMemory` | `memhtml manifest` | `apps/cli/src/errors.ts`, `apps/mcp/src/handlers.ts` |
| `ERR_DUPLICATE_CONTENT` | `DuplicateContent` | `memhtml read <path>` | `apps/cli/src/errors.ts` |
| `ERR_WRITE_CONFLICT` | `WriteConflict` | `memhtml read <path>`, `memhtml correct <path> --title <title> --claim <sentence>`, `re-apply the change to current content` | `apps/cli/src/errors.ts` |
| `ERR_DIRTY_TREE` | `DirtyTree` | `git -C $MEMHTML_ROOT status`, `commit or stash the changes, then retry` | `apps/cli/src/errors.ts` |
| `ERR_INDEX_STALE` | `IndexStale` | `memhtml index rebuild` | `apps/cli/src/errors.ts` |
| `ERR_EMBED_MODEL_MISMATCH` | `EmbedModelMismatch` | `memhtml index rebuild --embed` | `apps/cli/src/errors.ts` |
| `ERR_MODEL_UNAVAILABLE` | `ModelUnavailable` | `retry: search still works on the lexical floor`, `memhtml status` | `apps/cli/src/errors.ts` |
| `ERR_STORAGE` | `StorageFailure` | *none* | `apps/cli/src/errors.ts`, `apps/cli/src/integrations.ts` |
| `ERR_GIT` | `GitFailure` | *none* | `apps/cli/src/errors.ts` |
| `ERR_DISCRIMINATION_FAILED` | `DiscriminationFailed` | `memhtml eval discriminate`, `memhtml sleep review`, `git branch -D <run-id>` | `apps/cli/src/errors.ts` |
| `ERR_UNKNOWN` | - | *none* | `apps/cli/src/errors.ts`, `apps/cli/src/run.ts`, `apps/mcp/src/resources.ts` |
| `ERR_REBUILD_NO_EMBED_REFUSED` | `RebuildNoEmbedRefused` | `memhtml index rebuild --embed`, `memhtml index rebuild --no-embed --force`, `memhtml index embed` | `apps/cli/src/errors.ts` |
| `ERR_UNKNOWN_HOST` | - | *none* | `apps/cli/src/integrations.ts`, `apps/cli/src/run.ts` |
| `ERR_UNKNOWN_HOOK_EVENT` | - | *none* | `apps/cli/src/run.ts` |
| `ERR_INTEGRATION_MODIFIED` | `IntegrationModified` | `memhtml integrations doctor <host>`, `memhtml integrations install <host> --force` | `apps/cli/src/errors.ts` |

Every code is named somewhere in `apps/cli/src` or `apps/mcp/src`.

## 3. How a failure reaches a caller

The CLI translates every typed domain failure in one place, `apps/cli/src/errors.ts`. That translation covers every case: a failure it does not recognize becomes `ERR_UNKNOWN`, so a caller always gets a code to branch on. [The JSON envelope](/reference/envelope/) gives the shape the code arrives in.

## 4. Provenance

A loader generates this page from `apps/cli/src/envelope.ts` while the site builds, so no file in the repository holds it: the mapping column is read from the translation's own switch, and the last column is a census over `apps/cli/src` and `apps/mcp/src`. Change the registry and this page changes with it.