---
title: "Troubleshooting"
description: "Symptoms, causes and fixes for the errors verbatra actually raises, each listed under its error code, plus Studio and MCP install problems."
type: "reference"
---
# Troubleshooting

Symptoms, causes and fixes for the errors verbatra actually raises, each listed under its error code, plus Studio and MCP install problems.

Each entry starts from what you see and links the code behind it to [Error codes](https://verbatra.kreitz-webdev.de/docs/error-codes.md),
which lists every code with its meaning, exit code and next step. Search by the code in
`verbatra: error [CODE]`, never by the message text.

Run [`verbatra doctor`](https://verbatra.kreitz-webdev.de/docs/cli/doctor.md) before you go entry by entry: it checks the config, the
format, the provider, the API key variable and the source file in one pass, spends nothing, and
works before the source locale file exists.

## pnpm blocks a dependency's install scripts (ERR_PNPM_IGNORED_BUILDS) [#pnpm-blocks-a-dependencys-install-scripts-err_pnpm_ignored_builds]

**Symptom**: `pnpm add -D @verbatra/cli` prints its install summary and then exits `1`:

```
[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: @google/genai@3.1.0, protobufjs@7.6.5
Run "pnpm approve-builds" to pick which dependencies should be allowed to run scripts.
```

pnpm also writes a `pnpm-workspace.yaml` into your project holding an unanswered choice:

```yaml
allowBuilds:
  '@google/genai': set this to true or false
  protobufjs: set this to true or false
```

Until you answer it, every later pnpm command in that project fails the same way, including
`pnpm exec verbatra init`.

**Cause**: pnpm does not run a third-party dependency's install scripts unless you allow them.
`@google/genai` and its transitive `protobufjs` declare such scripts, and the Gemini SDK is
installed whichever provider you configure, so every pnpm install path hits this. Nothing in
verbatra declares an install script of its own, and npm and yarn install the same package without
a prompt. The install itself did complete: `node_modules/.bin/verbatra` already works.

**Fix**: answer the choice once. Interactively, run `pnpm approve-builds` and approve neither
entry. Non-interactively, which is what you want in CI, write the answer before you install by
putting this in `pnpm-workspace.yaml` at the project root:

```yaml
allowBuilds:
  '@google/genai': false
  protobufjs: false
```

verbatra does not need those scripts, and this repository declines both. With the answer in place
`pnpm add -D @verbatra/cli` exits `0` and later pnpm commands run normally. The package versions
in the message track the release; the fix does not change.

## The configuration is invalid (CONFIG_INVALID) [#the-configuration-is-invalid-config_invalid]

**Symptom**: `The verbatra configuration is invalid: ...`, with one issue per field.

**Cause**: the config was found but fails validation, for example a `files.pattern` without
`{locale}`, a locale code that is not BCP 47 (such as `en_US`), or an unknown key. An unknown key
gets the note `API keys are read from the environment, not the config`: the schema is strict so a
secret cannot hide in a committed file.

**Fix**: correct the field the message names; see [The config file](https://verbatra.kreitz-webdev.de/docs/config-file.md). For
`No verbatra configuration found...`, see [`CONFIG_NOT_FOUND`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#config_not_found).
Code: [`CONFIG_INVALID`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#config_invalid).

## No adapter for the format (UNKNOWN_FORMAT) [#no-adapter-for-the-format-unknown_format]

**Symptom**: `No adapter is registered for format "..."`, followed by the supported list.

**Cause**: the config's `format` is not a registered id. A `custom:` format cannot run from the
command line, which loads no plugin.

**Fix**: use an id from [Formats](https://verbatra.kreitz-webdev.de/docs/formats.md). For a `custom:` format, run through the SDK with a
registry that holds its adapter: see [Write a custom format adapter](https://verbatra.kreitz-webdev.de/docs/custom-format-adapters.md). Code:
[`UNKNOWN_FORMAT`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#unknown_format).

## Requested locale is not configured (UNKNOWN_LOCALE) [#requested-locale-is-not-configured-unknown_locale]

**Symptom**: `Requested locale not in the configured target locales: ...`

**Cause**: `--locales` (or an SDK `locales` input) names a locale that is not in `targetLocales`.
A filter selects from the configured list; it never adds to it.

**Fix**: add the locale to `targetLocales`, or fix the typo. Code:
[`UNKNOWN_LOCALE`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#unknown_locale).

## The source file is missing or unparseable (SOURCE_UNREADABLE, SOURCE_INVALID) [#the-source-file-is-missing-or-unparseable-source_unreadable-source_invalid]

**Symptom**: `The source locale file was not found at <path>.` or `The source locale file at
<path> could not be read: ...`

**Cause**: `files.pattern` with the source locale filled in points at no file, or the file does
not parse. The path is resolved against the project root, the directory of the config the search found
(or the working directory with `--config`), so a wrong `--cwd` or `--config` is a common cause, and so is a wildcard: `files.pattern` is a literal path, not a glob (see
[Namespace layouts](https://verbatra.kreitz-webdev.de/docs/formats.md#namespace-layouts)).

**Fix**: check the printed path. For a parse failure, the `causeCode` names the
[format adapter code](https://verbatra.kreitz-webdev.de/docs/error-codes.md#adapter-error-codes). Codes:
[`SOURCE_UNREADABLE`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#source_unreadable),
[`SOURCE_INVALID`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#source_invalid).

## Missing API key (PROVIDER_CONSTRUCTION_FAILED) [#missing-api-key-provider_construction_failed]

**Symptom**: `Failed to construct provider "anthropic": The ANTHROPIC_API_KEY environment variable
is not set.` (or your provider's variable).

**Cause**: the variable the message names is unset or empty. Keys come only from the environment,
never from the config or a flag.

**Fix**: set the variable and confirm it with `verbatra doctor`. The CLI also reads it from
[`.env.local` and `.env`](https://verbatra.kreitz-webdev.de/docs/cli.md#environment-files); the SDK does not, so use
`node --env-file=.env` in your own script. Codes:
[`PROVIDER_CONSTRUCTION_FAILED`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#provider_construction_failed),
[`MISSING_API_KEY`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#missing_api_key).

## Rate limits, timeouts, and auth failures mid-run (RATE_LIMITED, TIMEOUT, AUTH_FAILED) [#rate-limits-timeouts-and-auth-failures-mid-run-rate_limited-timeout-auth_failed]

**Symptom**: the run completes, but some keys are listed under `providerFailures` with a
`SUB_BATCH_FAILED` notice naming the provider code, and the command exits `1`.

**Cause**: a provider request failed after the provider was built: HTTP 429, a timeout, or HTTP
401/403.

**Fix**: nothing is lost; the keys are picked up again on the next run. Re-run later for
[`RATE_LIMITED`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#rate_limited), after the wait its message names if it names one
(an exhausted daily quota), and one locale at a time with `--locales` against a strict quota. For a slow model, raise
[`requestTimeoutMs`](https://verbatra.kreitz-webdev.de/docs/providers.md#request-timeout) against
[`TIMEOUT`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#timeout). [`AUTH_FAILED`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#auth_failed) does not
resolve by retrying: replace the key.

## The lock file is corrupt (LOCK_FILE_INVALID) [#the-lock-file-is-corrupt-lock_file_invalid]

**Symptom**: `The lock-file at <path> is not valid JSON.`, `... has an unexpected shape.`,
`... has version N ...`, or `... exceeds the maximum allowed size ...`

**Cause**: `verbatra.lock.json` was hand-edited, truncated, damaged in a merge, or written by an
incompatible version. `translate` and `import` stop the whole run on it, and locales committed
before the stop keep what they wrote.

**Fix**: restore the file from version control. Deleting it also clears the error, but loses the
baselines, so earlier source edits are no longer seen as stale. See
[The lock file](https://verbatra.kreitz-webdev.de/docs/the-lock-file.md). Code:
[`LOCK_FILE_INVALID`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#lock_file_invalid).

## A locale file could not be written (TARGET_UNWRITABLE) [#a-locale-file-could-not-be-written-target_unwritable]

**Symptom**: a locale fails with `Could not write the locale file locales/de.json (EACCES). ...`

**Cause**: the file or its directory is not writable: permissions, a missing directory, a
read-only mount, or a full disk. The write goes through a temporary file in the same directory, so
the directory must be writable too.

**Fix**: fix what the file-system code names and re-run. Only that locale fails, and it keeps its
previous file and baseline. Code: [`TARGET_UNWRITABLE`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#target_unwritable).

## Another process holds the write lock (LOCK_CONTENDED) [#another-process-holds-the-write-lock-lock_contended]

**Symptom**: `Could not acquire the write lock at <path>: another process is holding it. ...`

**Cause**: another `translate`, `watch`, `import` or Studio write holds the locale's lock. A lock
left by a dead process on this machine is reclaimed automatically, so a lingering one comes from
another machine or a verbatra older than 0.12.0.

**Fix**: wait for the other run, or delete the printed lock file if no verbatra process runs
anywhere. `--lock-timeout <seconds>` on [`translate`](https://verbatra.kreitz-webdev.de/docs/cli/translate.md),
[`watch`](https://verbatra.kreitz-webdev.de/docs/cli/watch.md) and [`import`](https://verbatra.kreitz-webdev.de/docs/cli/import.md) changes how long a run waits. Code:
[`LOCK_CONTENDED`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#lock_contended).

## Dotted keys or YAML keys collide (INVALID_STRUCTURE) [#dotted-keys-or-yaml-keys-collide-invalid_structure]

**Symptom**: `A dotted key and a nested key path resolve to the same path.`, or for YAML
`A mapping key is a map or sequence (expected scalar keys).`

**Cause**: two entries in one file resolve to the same key, such as `"a.b"` next to
`a: { b: ... }`, or a YAML key has no string form. verbatra refuses rather than dropping one.

**Fix**: rename one of the keys, or use a scalar YAML key. In the source file this arrives inside
`SOURCE_INVALID`. Code: [`INVALID_STRUCTURE`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#invalid_structure).

## The run stopped short of some keys (token budget) [#the-run-stopped-short-of-some-keys-token-budget]

**Symptom**: a `BUDGET_TOKENS_EXCEEDED` notice; under `budgetBehavior: "stop"` keys are also listed
under `budgetWithheld`.

**Cause**: the run reached `maxTokens` in the config or `--max-tokens` for the run. `"warn"` only
reports a budget set in the config; `"stop"`, and `--max-tokens` whatever the config says, withhold every key not yet attempted, and the locale ends `partial` or
`failed`.

**Fix**: this is the guardrail working: what landed is written, and withheld keys are translated
on the next run. Raise the budget or switch to `"warn"` for one-run completion. How the budget is
counted is in [Translation safety](https://verbatra.kreitz-webdev.de/docs/translation-safety.md#the-token-budget). Code:
[`BUDGET_TOKENS_EXCEEDED`](https://verbatra.kreitz-webdev.de/docs/error-codes.md#budget_tokens_exceeded).

## A translation is withheld for inline markup (integrity mismatch) [#a-translation-is-withheld-for-inline-markup-integrity-mismatch]

**Symptom**: a key is listed under `integrityMismatches` and keeps its previous value, or Studio
shows `Rejected: inline markup mismatch` with the tags at fault: `-<a href>` for a tag the
candidate dropped, `+<i>` for one it invented. `verbatra check --qa` reports the same for values
already on disk.

**Cause**: the candidate does not carry the source's inline tags, or carries them unbalanced or
mis-nested, so the integrity gate refuses it like a dropped placeholder.

**Fix**: run the key again, or fix the value by hand in Studio or a workbook; the same gate judges
both. What is compared, and the refusals that are by design, are in
[Inline markup parity](https://verbatra.kreitz-webdev.de/docs/translation-safety.md#inline-markup-parity).

## Studio: the port is already in use [#studio-the-port-is-already-in-use]

**Symptom**: `port 5849 is already in use` (or your `--port` value).

**Cause**: another process, often an earlier Studio, is bound to the port.

**Fix**: stop it, or start Studio on another port: `verbatra studio --port 6000`.

## Studio: @verbatra/studio is not installed [#studio-verbatrastudio-is-not-installed]

**Symptom**: `Verbatra Studio requires @verbatra/studio.`, followed by the install commands.

**Cause**: Studio is a separate package the `studio` command loads on demand.

**Fix**: `npm install --save-dev @verbatra/studio`, or for a one-off run
`npx -y -p @verbatra/cli -p @verbatra/studio verbatra studio`. With pnpm, see
[pnpm blocks a dependency's install scripts](#pnpm-blocks-a-dependencys-install-scripts-err_pnpm_ignored_builds)
first.

`npx @verbatra/cli` runs the CLI installed in the package of the current folder, so run it from
the project root (or use `pnpm exec verbatra` in a workspace subpackage); anywhere else npx fetches
the latest CLI, which may not match your local `@verbatra/studio` or `@verbatra/mcp`.

## Studio: retranslate and translate actions are missing [#studio-retranslate-and-translate-actions-are-missing]

**Symptom**: editing works, but the retranslate and translate-pending actions do not appear.

**Cause**: provider spend is granted at startup, under the rules in
[Spend and agent tools](https://verbatra.kreitz-webdev.de/docs/cli/studio.md#spend-and-agent-tools), and without it the spend actions
are not registered.

**Fix**: restart with `verbatra studio --allow-spend`, unless the project is
[human-only](https://verbatra.kreitz-webdev.de/docs/human-only-workflow.md). See [Review in Studio](https://verbatra.kreitz-webdev.de/docs/review-in-studio.md).

## MCP: @verbatra/mcp is not installed [#mcp-verbatramcp-is-not-installed]

**Symptom**: `Verbatra's MCP server requires @verbatra/mcp.`, followed by the install commands.

**Cause**: the MCP server is a separate package the `mcp` command loads on demand, so
`npx -y @verbatra/cli mcp` alone never works.

**Fix**: run `npx -y @verbatra/mcp`, or install `@verbatra/mcp` next to the CLI and re-run
`verbatra mcp`. With pnpm, see
[pnpm blocks a dependency's install scripts](#pnpm-blocks-a-dependencys-install-scripts-err_pnpm_ignored_builds)
first.

## MCP: an agent's tools/list never shows `translation.retranslateEntry` or `translation.translatePending` [#mcp-an-agents-toolslist-never-shows-translationretranslateentry-or-translationtranslatepending]

**Symptom**: the local tools work, but the two spend tools are absent, and calling one fails as an
unknown tool.

**Cause**: spend is granted at startup, under the rules in [Spend tools](https://verbatra.kreitz-webdev.de/docs/cli/mcp.md#spend-tools),
and the tool list must not change per connection, so the spend tools are left out entirely.

**Fix**: restart with `verbatra mcp --allow-spend`, unless the project is
[human-only](https://verbatra.kreitz-webdev.de/docs/human-only-workflow.md).

## Undoing a run (no error code) [#undoing-a-run-no-error-code]

verbatra has no undo command; version control is the recovery path. Revert the locale files,
`verbatra.lock.json` and `verbatra.provenance.json` together, never the locale files alone. See
[Recovery and rollback](https://verbatra.kreitz-webdev.de/docs/recovery-and-rollback.md).
