---
title: "Fehlercodes"
description: "Jeder Fehler-, Ergebnis- und Hinweiscode, den verbatra meldet: was er bedeutet, welche Befehle ihn auslösen, der Exit-Code und der nächste Schritt."
type: "reference"
---
# Fehlercodes

Jeder Fehler-, Ergebnis- und Hinweiscode, den verbatra meldet: was er bedeutet, welche Befehle ihn auslösen, der Exit-Code und der nächste Schritt.

Jeder Fehler, den verbatra meldet, trägt einen stabilen Code: in der Zeile `verbatra: error [CODE] message` auf stderr, als `code` oder `causeCode` eines `--json`-Envelopes, als `error.code` einer gescheiterten Locale oder als Hinweis in der Laufzusammenfassung. Verzweige auf den Code, nie auf die Meldung. Jeder Code hat seinen eigenen Anker, `/docs/error-codes#` gefolgt vom Code in Kleinbuchstaben, etwa [`#config_not_found`](#config_not_found).

Der **Nächste Schritt** eines Fehlercodes ist der Hinweis, den verbatra nach der Fehlerzeile als `next: ...` ausgibt und in das Feld `hint` des Envelopes schreibt. Er steht hier genau so, wie verbatra ihn ausgibt, auf Englisch, und das SDK liefert denselben Text aus [`errorHint`](https://verbatra.kreitz-webdev.de/de/docs/sdk/errors.md#errorhint). Die Exit-Codes selbst und die Form des Envelopes stehen auf [Exit-Codes und JSON-Ausgabe](https://verbatra.kreitz-webdev.de/de/docs/cli/output.md); Hilfe vom Symptom her findest du unter [Fehlerbehebung](https://verbatra.kreitz-webdev.de/de/docs/troubleshooting.md).

Zwei Codes gehören zu zwei Familien: `CONFIG_INVALID` (das SDK und `init` in der CLI) und `NETWORK_POLICY_VIOLATION` (das SDK und die Provider). Der Anker in Kleinbuchstaben führt zum SDK-Eintrag; der andere Eintrag hat einen Anker mit Präfix.

## Code-Index [#code-index]

Jeder Fehlercode mit seiner Familie und den Exit-Codes, mit denen er einen CLI-Lauf beenden kann; wann welcher gilt, sagt der Abschnitt seiner Familie.

| Code | Familie | Exit-Code |
| --- | --- | --- |
| [`AGENT_FILE_INVALID`](#agent_file_invalid) | CLI | `2` |
| [`CLI_ERROR`](#cli_error) | CLI | `2` |
| [`CONFIG_EXISTS`](#config_exists) | CLI | `2` |
| [`CONFIG_INVALID`](#cli-config_invalid) | CLI | `2` |
| [`FORMAT_AMBIGUOUS`](#format_ambiguous) | CLI | `2` |
| [`INIT_UNWRITABLE`](#init_unwritable) | CLI | `2` |
| [`INVALID_CONCURRENCY`](#invalid_concurrency) | CLI | `2` |
| [`INVALID_DEBOUNCE`](#invalid_debounce) | CLI | `2` |
| [`INVALID_DIRECTION`](#invalid_direction) | CLI | `2` |
| [`INVALID_FORMAT`](#invalid_format) | CLI | `2` |
| [`INVALID_LOCALE`](#invalid_locale) | CLI | `2` |
| [`INVALID_LOCALES`](#invalid_locales) | CLI | `2` |
| [`INVALID_LOCK_TIMEOUT`](#invalid_lock_timeout) | CLI | `2` |
| [`INVALID_MAX_TOKENS`](#invalid_max_tokens) | CLI | `2` |
| [`INVALID_OPTION`](#invalid_option) | CLI | `2` |
| [`INVALID_OUT`](#invalid_out) | CLI | `2` |
| [`INVALID_PORT`](#invalid_port) | CLI | `2` |
| [`INVALID_PROVIDER`](#invalid_provider) | CLI | `2` |
| [`INVALID_QA_OPTION`](#invalid_qa_option) | CLI | `2` |
| [`INVALID_SEVERITY`](#invalid_severity) | CLI | `2` |
| [`LAYOUT_AMBIGUOUS`](#layout_ambiguous) | CLI | `2` |
| [`MISSING_OPTIONS`](#missing_options) | CLI | `2` |
| [`REDACTION_UNSUPPORTED`](#redaction_unsupported) | CLI | `2` |
| [`USAGE_ERROR`](#usage_error) | CLI | `2` |
| [`CONFIG_NOT_FOUND`](#config_not_found) | SDK | `2` oder `1` |
| [`CONFIG_INVALID`](#config_invalid) | SDK | `2` oder `1` |
| [`UNKNOWN_FORMAT`](#unknown_format) | SDK | `2` oder `1` |
| [`UNKNOWN_LOCALE`](#unknown_locale) | SDK | `2` |
| [`UNKNOWN_KEY`](#unknown_key) | SDK | keiner |
| [`KEY_PROTECTED`](#key_protected) | SDK | keiner |
| [`KEY_PINNED`](#key_pinned) | SDK | keiner |
| [`PROVIDER_CONSTRUCTION_FAILED`](#provider_construction_failed) | SDK | `2` |
| [`MACHINE_TRANSLATION_DISABLED`](#machine_translation_disabled) | SDK | keiner |
| [`NETWORK_POLICY_VIOLATION`](#network_policy_violation) | SDK | `2` |
| [`SOURCE_UNREADABLE`](#source_unreadable) | SDK | `2` oder `1` |
| [`SOURCE_INVALID`](#source_invalid) | SDK | `2` oder `1` |
| [`LOCK_FILE_INVALID`](#lock_file_invalid) | SDK | `2` |
| [`PROVENANCE_FILE_INVALID`](#provenance_file_invalid) | SDK | `2` |
| [`PROVENANCE_FILE_UNWRITABLE`](#provenance_file_unwritable) | SDK | keiner |
| [`REVIEW_VALUE_CHANGED`](#review_value_changed) | SDK | keiner |
| [`REVIEW_SOURCE_CHANGED`](#review_source_changed) | SDK | keiner |
| [`REVIEW_REJECT_UNSUPPORTED`](#review_reject_unsupported) | SDK | keiner |
| [`REVIEW_RESTORE_FAILED`](#review_restore_failed) | SDK | keiner |
| [`REVIEWER_INVALID`](#reviewer_invalid) | SDK | `2` |
| [`LOCK_CONTENDED`](#lock_contended) | SDK | `1` |
| [`GLOSSARY_NOT_FILE_BACKED`](#glossary_not_file_backed) | SDK | keiner |
| [`GLOSSARY_UNWRITABLE`](#glossary_unwritable) | SDK | keiner |
| [`LOCALE_LAYOUT_INVALID`](#locale_layout_invalid) | SDK | `2` |
| [`LOCALE_PATH_COLLISION`](#locale_path_collision) | SDK | `2` |
| [`CONCURRENCY_INVALID`](#concurrency_invalid) | SDK | keiner |
| [`CONCURRENCY_BUDGET_CONFLICT`](#concurrency_budget_conflict) | SDK | `2` |
| [`MAX_TOKENS_INVALID`](#max_tokens_invalid) | SDK | keiner |
| [`LOCK_TIMEOUT_INVALID`](#lock_timeout_invalid) | SDK | keiner |
| [`PAGE_CURSOR_INVALID`](#page_cursor_invalid) | SDK | keiner |
| [`PAGE_LIMIT_INVALID`](#page_limit_invalid) | SDK | keiner |
| [`TARGET_UNWRITABLE`](#target_unwritable) | SDK | `1` oder `2` |
| [`PSEUDO_OUTPUT_CONFLICT`](#pseudo_output_conflict) | SDK | `2` |
| [`SOURCE_UNWRITABLE`](#source_unwritable) | SDK | `2` |
| [`EXTRACT_NOT_CONFIGURED`](#extract_not_configured) | SDK | `2` |
| [`EXTRACT_FS_UNSUPPORTED`](#extract_fs_unsupported) | SDK | keiner |
| [`TYPES_OUTPUT_CONFLICT`](#types_output_conflict) | SDK | `2` |
| [`TYPES_UNWRITABLE`](#types_unwritable) | SDK | `2` |
| [`TMX_OUTPUT_CONFLICT`](#tmx_output_conflict) | SDK | `2` |
| [`TMX_UNWRITABLE`](#tmx_unwritable) | SDK | `2` |
| [`MEMORY_UNWRITABLE`](#memory_unwritable) | SDK | `2` |
| [`EXPORT_OUTPUT_CONFLICT`](#export_output_conflict) | SDK | `2` |
| [`EXPORT_UNWRITABLE`](#export_unwritable) | SDK | `2` |
| [`LOCALE_STATE_NOT_CARRIED_OVER`](#locale_state_not_carried_over) | SDK | `1` |
| [`LOCALE_UNSUPPORTED_BY_PROVIDER`](#locale_unsupported_by_provider) | SDK | `2` |
| [`NOT_A_LOCALE_FILE`](#not_a_locale_file) | SDK | `2` |
| [`SENSITIVE_CONTENT_WITHHELD`](#sensitive_content_withheld) | SDK | keiner |
| [`RUN_CANCELLED`](#run_cancelled) | SDK | keiner |
| [`LOCALE_FAILED`](#locale_failed) | SDK | `1` |
| [`MISSING_API_KEY`](#missing_api_key) | Provider | `2` |
| [`INVALID_REQUEST`](#invalid_request) | Provider | `1` |
| [`INVALID_RESPONSE`](#invalid_response) | Provider | `1` |
| [`OUTPUT_TRUNCATED`](#output_truncated) | Provider | `1` |
| [`PROVIDER_REFUSED`](#provider_refused) | Provider | `1` |
| [`PROVIDER_BLOCKED`](#provider_blocked) | Provider | `1` |
| [`RATE_LIMITED`](#rate_limited) | Provider | `1` |
| [`TIMEOUT`](#timeout) | Provider | `1` |
| [`AUTH_FAILED`](#auth_failed) | Provider | `1` |
| [`PROVIDER_UNAVAILABLE`](#provider_unavailable) | Provider | `1` |
| [`NETWORK_POLICY_VIOLATION`](#provider-network_policy_violation) | Provider | `1` |
| [`PROVIDER_ERROR`](#provider_error) | Provider | `1` |
| [`INVALID_JSON`](#invalid_json) | Formatadapter | `1` oder `2` |
| [`INVALID_YAML`](#invalid_yaml) | Formatadapter | `1` oder `2` |
| [`INVALID_XML`](#invalid_xml) | Formatadapter | `1` oder `2` |
| [`INVALID_STRUCTURE`](#invalid_structure) | Formatadapter | `1` oder `2` |
| [`MAX_DEPTH_EXCEEDED`](#max_depth_exceeded) | Formatadapter | `1` oder `2` |
| [`INPUT_TOO_LARGE`](#input_too_large) | Formatadapter | `1` oder `2` |
| [`MIXED_STRUCTURE`](#mixed_structure) | Formatadapter | `1` oder `2` |
| [`ADAPTER_FAILED`](#adapter_failed) | Formatadapter | keiner |
| [`DUPLICATE_FORMAT`](#duplicate_format) | Formatadapter | keiner |
| [`INVALID_FORMAT_ID`](#invalid_format_id) | Formatadapter | keiner |

## CLI-Fehlercodes [#cli-error-codes]

Diese Codes löst die CLI selbst aus. Dieselbe Liste wird als `CLI_ERROR_CODES` (mit dem Typ `CliErrorCode`) aus `@verbatra/cli` ausgeliefert. Jeder von ihnen endet mit Exit-Code `2`.

### AGENT_FILE_INVALID [#agent_file_invalid]

`init --agent` eine Client-Konfiguration (`.mcp.json`, `.cursor/mcp.json`, `.vscode/mcp.json` oder `.gemini/settings.json`) gefunden hat, die kein reines JSON ist, kein Objekt ist oder einen Server-Wert enthält, der kein Objekt ist, eine `.codex/config.toml`, die es nicht sicher lesen kann oder die den verbatra-Server inline, mit gepunkteten Schlüsseln, als Array von Tabellen oder doppelt setzt, einen symbolischen Link auf einem Pfad, den es schreiben würde, oder eine unpaarige oder doppelte verbatra-Markierung in `AGENTS.md` oder `CLAUDE.md`; es wurde nichts geschrieben.

- **Ausgelöst von**: `init --agent`
- **Nächster Schritt**: Repair the MCP config or the verbatra markers in the file the message names, or replace the symbolic link it names with a plain file, then run `verbatra init --agent` again.

### CLI_ERROR [#cli_error]

Ein Fehlschlag keinen eigenen Code mitbrachte (der Ausweich-Code).

- **Ausgelöst von**: jeder Befehl

### CONFIG_EXISTS [#config_exists]

`init` ohne `--force` eine abweichende `verbatra.config.ts` überschreiben würde oder eine andere verbatra-Konfigurationsdatei im Verzeichnis zuerst gelesen würde; wird vor jeder fehlenden oder mehrdeutigen Antwort gemeldet, im Terminal schon vor der ersten Frage.

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Edit the existing config, or pass --force to replace verbatra.config.ts; remove any other config file the message names first.

### CONFIG_INVALID [#cli-config_invalid]

`init` aus den erhaltenen Antworten keine gültige Konfiguration erzeugen konnte (das SDK löst denselben Code für eine Konfiguration aus, die sich nicht laden lässt).

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Correct the init answers the message names, then run `verbatra init` again.

### FORMAT_AMBIGUOUS [#format_ambiguous]

`init` mehrere Formate gefunden hat, die die Locale-Dateien lesen; `candidates` listet sie auf.

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Pass --format with one of the candidates.

### INIT_UNWRITABLE [#init_unwritable]

`init` eine Datei nicht in sein Verzeichnis schreiben konnte, etwa weil es schreibgeschützt ist oder eine Datei, die es schreibt, ein symbolischer Link ist, der nicht innerhalb des Projekts aufgelöst wird; die Meldung nennt die Datei, die Ursache und die bereits geschriebenen Dateien.

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Make the directory writable, or replace the symbolic link the message names with a plain file, then run `verbatra init` again.

### INVALID_CONCURRENCY [#invalid_concurrency]

`--concurrency` keine ganze Zahl zwischen 1 und 100 ist.

- **Ausgelöst von**: `translate`, `watch`
- **Nächster Schritt**: Pass --concurrency as a whole number from 1 to 100.

### INVALID_DEBOUNCE [#invalid_debounce]

`watch --debounce` keine ganze Zahl von Millisekunden zwischen 1 und 60000 ist.

- **Ausgelöst von**: `watch`
- **Nächster Schritt**: Pass --debounce as a whole number of milliseconds from 1 to 60000.

### INVALID_DIRECTION [#invalid_direction]

`tmx` eine andere Richtung als `import` oder `export` bekommen hat oder `tmx export` ein Flag nur für den Import (`--dry-run`, `--overwrite`).

- **Ausgelöst von**: `tmx`
- **Nächster Schritt**: Run `verbatra tmx import` or `verbatra tmx export`, with only the flags that direction takes.

### INVALID_FORMAT [#invalid_format]

`--format` bei `export` oder `import` kein unterstütztes Übergabeformat nennt oder `--format` bei `init` kein unterstütztes Format für Locale-Dateien.

- **Ausgelöst von**: `export`, `import`, `init`
- **Nächster Schritt**: Pass a supported --format value; the command's --help lists them.

### INVALID_LOCALE [#invalid_locale]

`pseudo --locale` kein Sprach-Tag aus Buchstaben, Ziffern und Bindestrichen ist oder eine Locale, die bei einer interaktiven `init`-Abfrage eingegeben wurde, kein BCP-47-Code ist (die Flags `--source` und `--targets` scheitern stattdessen mit `CONFIG_INVALID`).

- **Ausgelöst von**: `pseudo`, `init`
- **Nächster Schritt**: Give the locale as a language tag of letters, digits and hyphens, such as pt-BR or en-XA.

### INVALID_LOCALES [#invalid_locales]

`--locales` angegeben wurde, aber keine Locale auflistet, oder die bei einer interaktiven `init`-Abfrage eingegebenen Ziel-Locales die Quell-Locale enthalten.

- **Ausgelöst von**: `translate`, `watch`, `check`, `diff`, `export`, `tmx`, `report`, `init`
- **Nächster Schritt**: Pass --locales as a comma-separated list of configured target locales, or omit it.

### INVALID_LOCK_TIMEOUT [#invalid_lock_timeout]

`--lock-timeout` keine ganze Zahl von Sekunden zwischen 1 und 3600 ist.

- **Ausgelöst von**: `translate`, `watch`, `import`
- **Nächster Schritt**: Pass --lock-timeout as a whole number of seconds from 1 to 3600.

### INVALID_MAX_TOKENS [#invalid_max_tokens]

`translate --max-tokens` keine ganze Zahl von mindestens 1 ist.

- **Ausgelöst von**: `translate`
- **Nächster Schritt**: Pass --max-tokens as a whole number of at least 1.

### INVALID_OPTION [#invalid_option]

Ein `init`-Flag passt nicht zum Provider oder ist fehlerhaft: `--base-url` ohne `openai-compatible` oder `libretranslate`, keine URL oder mit Zugangsdaten, einem Query-String oder einem Fragment; `--api-key-env-var` mit einem anderen Provider als `openai-compatible` oder kein Variablenname; `--model` bei einem Provider ohne Modell (`deepl`, `google-translate`, `libretranslate`, `none`); ein beliebiges Flag mit leerem Wert; `--targets` ohne Locale; `--path` ohne `{locale}`; `--client` ohne `--agent`, ohne Client oder mit einem Client, den init nicht einrichten kann. Oder `--cwd` nennt kein vorhandenes Verzeichnis (bei jedem Befehl, bevor er läuft), `doctor --data-flow` kommt mit `--literals`, `--locales` oder `--live`, `doctor --literals` kommt mit `--locales` oder `--live`, `check --file` nennt keine Datei oder kommt mit `--locales`, `--consistency`, `--require-reviewed` oder `--sensitive`, oder `pseudo --mode` nennt einen anderen Modus als `accented` oder `bidi`.

- **Ausgelöst von**: jedem Befehl mit `--cwd`, dazu `init`, `doctor`, `check`, `pseudo`
- **Nächster Schritt**: Correct or remove the flag the message names.

### INVALID_OUT [#invalid_out]

`--out` bei `types` oder `pseudo` angegeben wurde, aber keinen Pfad nennt.

- **Ausgelöst von**: `types`, `pseudo`
- **Nächster Schritt**: Pass --out with a file path, or omit it.

### INVALID_PORT [#invalid_port]

`studio --port` keine ganze Zahl zwischen 1 und 65535 ist.

- **Ausgelöst von**: `studio`
- **Nächster Schritt**: Pass --port as a whole number from 1 to 65535.

### INVALID_PROVIDER [#invalid_provider]

`init --provider` keinen bekannten Provider nennt.

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Pass --provider with a supported provider id; `verbatra init --help` lists them.

### INVALID_QA_OPTION [#invalid_qa_option]

`check` `--severity` oder `--strict` ohne `--qa` oder `--file` bekommen hat, oder `--strict` zusammen mit `--severity error`.

- **Ausgelöst von**: `check`
- **Nächster Schritt**: Add --qa or --file, and do not combine --strict with --severity error.

### INVALID_SEVERITY [#invalid_severity]

`check --severity` weder `error` noch `warning` ist.

- **Ausgelöst von**: `check`
- **Nächster Schritt**: Pass --severity error or --severity warning.

### LAYOUT_AMBIGUOUS [#layout_ambiguous]

`init` mehrere Dateimuster gefunden hat, die gleich gut passen; `candidates` listet sie auf.

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Pass --path with one of the candidates.

### MISSING_OPTIONS [#missing_options]

`init` nicht fragen konnte (kein Terminal oder `--json`) und ein Wert weder übergeben noch erkannt noch durch `--yes` mit einem Default gefüllt wurde; die Meldung nennt jedes fehlende Flag.

- **Ausgelöst von**: `init`
- **Nächster Schritt**: Pass the flags the message names, or --yes where the message offers it.

### REDACTION_UNSUPPORTED [#redaction_unsupported]

`mcp --redact-values` hat ein älteres `@verbatra/mcp` geladen, das nicht bestätigt, dass es Werte schwärzt; der Server wurde gestoppt, bevor er etwas ausgeliefert hat.

- **Ausgelöst von**: `mcp`
- **Nächster Schritt**: Upgrade @verbatra/mcp to the version that ships with this CLI, then start `verbatra mcp --redact-values` again.

### USAGE_ERROR [#usage_error]

Der Argument-Parser die Befehlszeile abgelehnt hat (eine unbekannte Option, ein fehlendes Argument) oder `mcp` Optionen bekommen hat, die es nicht annehmen kann; sein `hint` nennt das `--help` des Befehls.

- **Ausgelöst von**: jeder Befehl
- **Nächster Schritt**: Run the command with --help to see the options and arguments it accepts.

## SDK-Fehlercodes [#sdk-error-codes]

Fehler, die einen ganzen Lauf betreffen, werfen einen `SdkError` mit einem dieser Codes; [Fehler](https://verbatra.kreitz-webdev.de/de/docs/sdk/errors.md) beschreibt die Klasse und welche Codes ein `cause` tragen. In der CLI beendet ein geworfener Code den Lauf mit `2`, ein Code auf einer einzelnen gescheiterten Locale endet mit `1`. Wo der Index `2` oder `1` nennt, meldet `doctor` den Code als gescheiterte Prüfung und endet mit `1`. Codes ohne CLI-Befehl erreichen dich über das SDK, Studio oder den MCP-Server.

### CONFIG_NOT_FOUND [#config_not_found]

Die Suche fand keine Konfiguration, oder ein explizites `configPath` existiert nicht (geworfen von `loadConfig`).

- **Ausgelöst von**: jeder Befehl, der die Konfiguration lädt
- **Nächster Schritt**: Run `verbatra init` to create a config, or pass the path of an existing config file.

### CONFIG_INVALID [#config_invalid]

Eine Konfiguration wurde gefunden, ist aber nicht parsebar oder fällt durch die Validierung, oder ihre Glossardatei konnte nicht aufgelöst werden; `translate` (auch als Dry-Run, außer beim Provider `none`) und `retranslateEntry` werfen ihn außerdem, wenn `VERBATRA_NETWORK_POLICY` oder `VERBATRA_NETWORK_ALLOWED_HOSTS` einen ungültigen Wert enthält, bevor ein Provider gebaut wird.

- **Ausgelöst von**: jeder Befehl, der die Konfiguration lädt
- **Nächster Schritt**: Fix the config field the message names, then run `verbatra doctor` to confirm the setup.

### UNKNOWN_FORMAT [#unknown_format]

Für das konfigurierte Format ist kein Adapter registriert; geworfen, bevor irgendeine Datei gelesen wird.

- **Ausgelöst von**: jeder Befehl, der Locale-Dateien liest; Studio und der MCP-Server
- **Nächster Schritt**: Set `format` in the config to a supported format, or register an adapter for this one.

### UNKNOWN_LOCALE [#unknown_locale]

Eine angefragte Locale gehört nicht zu den konfigurierten Ziel-Locales.

- **Ausgelöst von**: `translate`, `watch`, `check`, `diff`, `export`, `tmx`, `report`; Studio und der MCP-Server
- **Nächster Schritt**: Use a locale from the config's `targetLocales`, or add it there first.

### UNKNOWN_KEY [#unknown_key]

Ein angefragter Key ist nicht in der Quell-Ressource (`keyValue`, `keyIntegrity`, `editEntry`, `retranslateEntry`, `approveEntry`, `rejectEntry`).

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Use a key that exists in the source locale file, or add it there first.

### KEY_PROTECTED [#key_protected]

`retranslateEntry` hat es abgelehnt, einen Wert zu ersetzen, den ein Mensch geschrieben, importiert oder außerhalb von verbatra geändert hat, weil weder `includeHuman` noch `humanEdits: "overwrite"` es erlaubt hat.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Keep the human-written value, or opt in to replacing it: include human edits for this call, or set `humanEdits: "overwrite"` in the config.

### KEY_PINNED [#key_pinned]

Der Key passt auf die `pinnedKeys` der Konfiguration, also wurde ein maschineller Schreibvorgang abgelehnt (`retranslateEntry` und `editEntry` mit `actor: "agent"`).

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Edit the value by hand, or remove the key from `pinnedKeys` in the config to let verbatra write it.

### PROVIDER_CONSTRUCTION_FAILED [#provider_construction_failed]

Der Provider konnte nicht gebaut werden; umhüllt den eigenen Fehler des Providers, einschließlich eines fehlenden API-Keys. Bei einem fehlenden Key nennt der Hinweis statt des nächsten Schritts unten die Variable, etwa `Set GEMINI_API_KEY in the environment, or, with the CLI, in a .env file in the project directory.` Das SDK liest keine `.env`-Datei.

- **Ausgelöst von**: `translate`, `watch`; Studio und der MCP-Server
- **Nächster Schritt**: Check the config's `provider` block and its API key environment variable, then run `verbatra doctor`.

### MACHINE_TRANSLATION_DISABLED [#machine_translation_disabled]

Die Konfiguration setzt `provider: { id: "none" }`, also wurde eine kostenpflichtige Provider-Aktion abgelehnt, bevor ein Provider gebaut wurde (`retranslateEntry`, `assertMachineTranslationEnabled`); `translate` und `watch` werfen ihn nie.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Translate the key by hand, or configure a machine provider in place of `provider: { id: "none" }`.

### NETWORK_POLICY_VIOLATION [#network_policy_violation]

Die wirksame [Netzwerkrichtlinie](https://verbatra.kreitz-webdev.de/de/docs/network-policy.md) erlaubt den Endpunkt des Providers oder seinen Proxy nicht; geworfen von `translate` außerhalb eines Probelaufs, von `watch` beim Start und von `retranslateEntry`, bevor der Provider gebaut oder ein API-Key gelesen wird.

- **Ausgelöst von**: `translate`, `watch`; Studio und der MCP-Server
- **Nächster Schritt**: Point the provider at a host the network policy permits, or add its host to `network.allowedHosts` or VERBATRA_NETWORK_ALLOWED_HOSTS.

### SOURCE_UNREADABLE [#source_unreadable]

Die Quell-Locale-Datei existiert nicht, oder bei `import` und `tmx import` die zu importierende Datei bzw. das Verzeichnis.

- **Ausgelöst von**: jeder Befehl, der Locale-Dateien liest; Studio und der MCP-Server
- **Nächster Schritt**: Create the source locale file, or fix `files.pattern` and `sourceLocale` in the config so they point at it.
- **Nächster Schritt bei `import`**: Pass the path of the filled handoff file, or of the directory it was exported into, relative to the working directory or `--cwd`.
- **Nächster Schritt bei `tmx import`**: Pass the path of an existing TMX file, relative to the working directory or `--cwd`.

### SOURCE_INVALID [#source_invalid]

Die Quell-Locale-Datei konnte nicht gelesen oder geparst werden; umhüllt den Lesefehler des Adapters. Bei `import` und `tmx import` ist die zu importierende Datei zu groß oder kein lesbares Übergabe- bzw. TMX-Dokument.

- **Ausgelöst von**: jeder Befehl, der Locale-Dateien liest; Studio und der MCP-Server
- **Nächster Schritt**: Fix the file the message names so it parses under the configured format.
- **Nächster Schritt bei `import`**: Fix the handoff file the message names, or pass its format with `--format` when its extension names none.
- **Nächster Schritt bei `tmx import`**: Fix the TMX file the message names, or export it again from the tool that wrote it.

### LOCK_FILE_INVALID [#lock_file_invalid]

Die Lock-Datei ist vorhanden, aber korrupt, übergroß oder in einer nicht unterstützten Version.

- **Ausgelöst von**: `translate`, `import`, `check`, `diff`, `export`, `report`; Studio und der MCP-Server
- **Nächster Schritt**: Restore verbatra.lock.json from version control, then try again.

### PROVENANCE_FILE_INVALID [#provenance_file_invalid]

Die Herkunftsdatei ist vorhanden, aber korrupt, übergroß oder falsch aufgebaut; geworfen von einem Schreibvorgang (`translate`, `watch`, `importWorkbook`, `editEntry`, `retranslateEntry`, `approveEntry`, `rejectEntry`), bevor er etwas ändert, und von `loadProvenance`, nie von einem Bericht; eine von einem neueren verbatra bleibt stattdessen unangetastet, und `translate`, `watch` und `importWorkbook` melden die Notice `PROVENANCE_VERSION_UNRECOGNIZED`.

- **Ausgelöst von**: `translate`, `watch`, `import`; Studio und der MCP-Server
- **Nächster Schritt**: Restore verbatra.provenance.json from version control, then try again.

### PROVENANCE_FILE_UNWRITABLE [#provenance_file_unwritable]

Eine Review-Entscheidung ließ sich nicht speichern, weil die Herkunftsdatei von einem neueren verbatra stammt oder über die Größe wachsen würde, die verbatra wieder einliest (`approveEntry`, `rejectEntry`, `approveLocale`); nichts wird geschrieben.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Upgrade verbatra if a newer version wrote verbatra.provenance.json, then record the decision again.

### REVIEW_VALUE_CHANGED [#review_value_changed]

Der Key hat keinen Wert, oder sein Wert ist nicht der `expectedValue`, den die prüfende Person gesehen hat, oder `expectedValue` ist kein String (`approveEntry`, `rejectEntry`).

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Reload the current value, review it again, and resend the decision.

### REVIEW_SOURCE_CHANGED [#review_source_changed]

Die Quelle hat sich geändert, seit der Wert geschrieben wurde, also lässt er sich so nicht freigeben (`approveEntry`).

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Edit or retranslate the key first, then review its new value.

### REVIEW_REJECT_UNSUPPORTED [#review_reject_unsupported]

Das Format behält den Wert eines Keys, wenn die Datei ohne ihn geschrieben wird, wie XLIFF, oder die Locale-Datei ist zu groß, um eine Kopie zum Wiederherstellen aufzuheben, also hat `rejectEntry` die Datei gelassen, wie sie war.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Edit the value instead of rejecting it.

### REVIEW_RESTORE_FAILED [#review_restore_failed]

`rejectEntry` ist nach dem Umschreiben der Locale-Datei gescheitert, und auch das Wiederherstellen der Locale-Datei oder der Herkunftsdatei schlug fehl; die Message nennt den ursprünglichen Fehler (auch die `cause`) und die Dateien, die du aus der Versionskontrolle wiederherstellst.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Restore the files the message names from version control.

### REVIEWER_INVALID [#reviewer_invalid]

`reviewer` ist leer, länger als 64 Zeichen oder enthält ein Steuerzeichen (`approveEntry`, `rejectEntry`, `approveLocale`, `importWorkbook`).

- **Ausgelöst von**: `import --reviewer`; Studio und der MCP-Server
- **Nächster Schritt**: Pass a reviewer name of 1 to 64 characters with no control characters.

### LOCK_CONTENDED [#lock_contended]

Die Schreibsperre einer Locale oder die Glossarsperre, die `updateGlossaryTerm` nimmt, konnte nicht vor ihrem Timeout erworben werden, oder ein anderer Prozess hat sie vor einem Schreibvorgang übernommen, den sie schützt, und es wurde nichts geschrieben; die Message nennt den Pfad der Lock-Datei.

- **Ausgelöst von**: `translate`, `watch`, `import`; Studio und der MCP-Server
- **Nächster Schritt**: Wait for the other verbatra process to finish and try again, or remove the lock file the message names if no process holds it.

### GLOSSARY_NOT_FILE_BACKED [#glossary_not_file_backed]

Das Glossar der Konfiguration ist inline oder fehlt, es gibt also keine Glossardatei zum Lesen oder Neuschreiben (`readGlossaryFile`, `updateGlossaryTerm`). Ist gar kein Glossar konfiguriert, lautet der Hinweis stattdessen: Create a glossary file, such as glossary.json holding `{}`, and set the config's `glossary` to its path, such as `"glossary.json"`.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Move the glossary into its own file and set the config's `glossary` to that file's path.

### GLOSSARY_UNWRITABLE [#glossary_unwritable]

Die Glossardatei konnte nicht geschrieben oder die Glossar-Schreibsperre nicht angelegt werden, etwa in einem schreibgeschützten Projekt, oder nach einer gespeicherten Änderung nicht freigegeben werden (`updateGlossaryTerm`); der Dateisystem-Fehler ist die `cause`.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Make the glossary file and its directory writable, then try again.

### LOCALE_LAYOUT_INVALID [#locale_layout_invalid]

`files.pattern` und `files.localeStyle` lassen sich nicht kombinieren, oder der Style hat keine gültige Pfadschreibweise für eine konfigurierte Locale.

- **Ausgelöst von**: jeder Befehl, der Locale-Dateien liest; Studio und der MCP-Server
- **Nächster Schritt**: Fix `files.pattern` and `files.localeStyle` in the config so every locale maps to a valid path.

### LOCALE_PATH_COLLISION [#locale_path_collision]

Zwei konfigurierte Locales lösen auf denselben absoluten Dateipfad auf.

- **Ausgelöst von**: jeder Befehl, der Locale-Dateien liest; Studio und der MCP-Server
- **Nächster Schritt**: Change `files.pattern` or `files.localeStyle` in the config so each locale resolves to its own file.

### CONCURRENCY_INVALID [#concurrency_invalid]

`concurrency` wurde gesetzt, ist aber keine Ganzzahl von mindestens 1; wird geworfen, bevor eine Locale läuft.

- **Ausgelöst von**: nur das SDK
- **Nächster Schritt**: Pass a concurrency that is a whole number of at least 1.

### CONCURRENCY_BUDGET_CONFLICT [#concurrency_budget_conflict]

Ein Live-Lauf setzte `concurrency` über 1, während ein Token-Budget gilt, konfiguriert oder für den Lauf; wird geworfen, bevor irgendein Provider-Aufruf stattfindet (ein Dry-Run ist ausgenommen).

- **Ausgelöst von**: `translate`, `watch`
- **Nächster Schritt**: Run with a concurrency of 1 while a token budget applies, or remove the budget.

### MAX_TOKENS_INVALID [#max_tokens_invalid]

Das `maxTokens` pro Lauf von `translate` wurde gesetzt, ist aber keine ganze Zahl von mindestens 1; wird geworfen, bevor irgendetwas gelesen oder ausgegeben wird.

- **Ausgelöst von**: nur das SDK
- **Nächster Schritt**: Pass a token budget that is a whole number of at least 1.

### LOCK_TIMEOUT_INVALID [#lock_timeout_invalid]

`lockAcquireTimeoutMs` wurde gesetzt, ist aber keine ganze Zahl von mindestens 0 Millisekunden (`translate`, `watch` beim Start, `importWorkbook`, `retranslateEntry`, `retranslateEntries`, `approveEntry`, `rejectEntry`, `approveEntries`, `rejectEntries`); wird geworfen, bevor irgendetwas gelesen oder gesperrt wird.

- **Ausgelöst von**: nur das SDK
- **Nächster Schritt**: Pass a lock timeout that is a whole number of at least 0.

### PAGE_CURSOR_INVALID [#page_cursor_invalid]

Der an `localeValuesPage` oder `provenanceReportPage` übergebene `cursor` ist fehlerhaft, länger als `PAGE_CURSOR_MAX_LENGTH` (512), stammt aus anderen Filtern oder zeigt auf einen Key, der verschoben wurde oder fehlt, weil sich die Dateien zwischen zwei Seiten geändert haben.

- **Ausgelöst von**: das SDK; das Agent-Tool `verbatra_locale_values` in Studio (der MCP-Server meldet ihn als ungültige Eingabe für `cursor`)
- **Nächster Schritt**: Call again without a cursor to start from the first page.

### PAGE_LIMIT_INVALID [#page_limit_invalid]

Das an `localeValuesPage` oder `provenanceReportPage` übergebene `limit` ist keine ganze Zahl von 1 bis `PAGE_LIMIT_CAP` (1000).

- **Ausgelöst von**: nur das SDK
- **Nächster Schritt**: Pass a page limit that is a whole number from 1 to 1000.

### TARGET_UNWRITABLE [#target_unwritable]

Eine Ziel-Locale-Datei konnte nicht geschrieben werden (ihr Verzeichnis ist nicht schreibbar, existiert nicht, ist schreibgeschützt oder hat keinen Platz mehr); die Message nennt die Zieldatei und den Dateisystem-Code, nie die interne temporäre Datei, die der atomare Schreibvorgang nutzt.

- **Ausgelöst von**: `translate`, `import`, `pseudo`; Studio und der MCP-Server
- **Nächster Schritt**: Make the target locale file and its directory writable, then try again.

### PSEUDO_OUTPUT_CONFLICT [#pseudo_output_conflict]

`pseudolocalize` wurde nach einer Pseudo-Locale gefragt, die eine konfigurierte Locale benennt, oder nach einem Ausgabepfad, der auf eine konfigurierte Locale-Datei oder außerhalb von `cwd` schreiben würde, auch nach dem Auflösen symbolischer Links; wird abgelehnt, bevor irgendetwas gelesen oder geschrieben wird.

- **Ausgelöst von**: `pseudo`
- **Nächster Schritt**: Choose a pseudolocale and an output path inside the project that name no configured locale.

### SOURCE_UNWRITABLE [#source_unwritable]

Die Quell-Locale-Datei konnte nicht geschrieben werden (nur `extract`); `xliff` und `apple-xcstrings` erreichen ihn, wenn noch kein Katalog existiert, denn keines von beiden wird aus dem Nichts erzeugt.

- **Ausgelöst von**: `extract`
- **Nächster Schritt**: Make the source locale file writable; for xliff and apple-xcstrings, create the catalog first.

### EXTRACT_NOT_CONFIGURED [#extract_not_configured]

`extract` wurde mit einer Konfiguration aufgerufen, die keinen `extract`-Block trägt.

- **Ausgelöst von**: `extract`
- **Nächster Schritt**: Add an `extract` block to the config naming the framework and source roots.

### EXTRACT_FS_UNSUPPORTED [#extract_fs_unsupported]

`extract` bekam ein `deps.fs`, das kein `readDirectory` implementiert, es kann also keine Quelldatei gefunden werden.

- **Ausgelöst von**: nur das SDK
- **Nächster Schritt**: Pass a file system that implements `readDirectory`, or use the default one.

### TYPES_OUTPUT_CONFLICT [#types_output_conflict]

`generateTypes` hat seinen Ausgabepfad abgelehnt: einen, der keine Datei benennt (oder auf ein Pfadtrennzeichen endet), absolut ist, mit `..` aus `cwd` herausklettert oder `cwd` selbst benennt oder nicht auf `.ts`, `.mts` oder `.cts` endet, und einen, der eine konfigurierte Locale-Datei, die Lock-Datei, die Herkunftsdatei, den Übersetzungsspeicher-Cache, eine Datei, nach der verbatra seine Konfiguration sucht, die geladene Konfigurationsdatei oder die Glossardatei der Konfiguration benennt, auch nach dem Auflösen symbolischer Links; ein schreibender Lauf weigert sich zusätzlich, eine vorhandene Datei zu ersetzen, die nicht mit verbatras Kopfzeile beginnt.

- **Ausgelöst von**: `types`
- **Nächster Schritt**: Choose a relative `.ts`, `.mts` or `.cts` output path inside the project that names no file verbatra manages.

### TYPES_UNWRITABLE [#types_unwritable]

Die von `generateTypes` erzeugte Deklarationsdatei konnte nicht geschrieben werden (ihr Verzeichnis ist nicht schreibbar, existiert nicht, oder die Platte ist voll); die Message nennt die Datei und den Dateisystem-Code.

- **Ausgelöst von**: `types`
- **Nächster Schritt**: Make the output file and its directory writable, then try again.

### TMX_OUTPUT_CONFLICT [#tmx_output_conflict]

`exportTmx` hat seinen Ausgabepfad abgelehnt: einen, der keine Datei benennt (oder auf ein Pfadtrennzeichen endet) oder außerhalb von `cwd` oder auf `cwd` selbst landet, und einen, der eine von verbatra verwaltete Datei benennt, wie unter [`TYPES_OUTPUT_CONFLICT`](#types_output_conflict) aufgeführt, auch nach dem Auflösen symbolischer Links; wird abgelehnt, bevor der Übersetzungsspeicher gelesen wird.

- **Ausgelöst von**: `tmx export`
- **Nächster Schritt**: Choose an output path inside the project that names no locale file or other file verbatra manages.

### TMX_UNWRITABLE [#tmx_unwritable]

Die von `exportTmx` erzeugte TMX-Datei konnte nicht geschrieben werden (ihr Verzeichnis ist nicht schreibbar, an dem Pfad liegt schon ein Verzeichnis, oder die Platte ist voll); die Message nennt die Datei und den Dateisystem-Code.

- **Ausgelöst von**: `tmx export`
- **Nächster Schritt**: Make the output file and its directory writable, then try again.

### MEMORY_UNWRITABLE [#memory_unwritable]

Die Translation-Memory-Cache-Datei `verbatra.cache.json` konnte von `importTmx` nicht geschrieben werden (ihr Verzeichnis ist nicht beschreibbar, an ihrem Pfad liegt bereits ein Verzeichnis, oder der Speicherplatz ist erschöpft); die Meldung nennt die Datei und den Dateisystem-Code.

- **Ausgelöst von**: `tmx import`
- **Nächster Schritt**: Make verbatra.cache.json and its directory writable, then try again.

### EXPORT_OUTPUT_CONFLICT [#export_output_conflict]

`exportWorkbook` hat seinen Ausgabepfad abgelehnt: einen, der außerhalb von `cwd` landet, und einen, der selbst oder über eine Datei, die der Export hineinschreiben würde, eine von verbatra verwaltete Datei benennt, wie unter [`TYPES_OUTPUT_CONFLICT`](#types_output_conflict) aufgeführt, auch nach dem Auflösen symbolischer Links; ein `xlsx`-Pfad, der keine Datei oder `cwd` selbst benennt, wird ebenfalls abgelehnt; wird abgelehnt, bevor irgendetwas gelesen wird.

- **Ausgelöst von**: `export`
- **Nächster Schritt**: Choose an output path inside the project that names no locale file or other file verbatra manages.

### EXPORT_UNWRITABLE [#export_unwritable]

Die von `exportWorkbook` erzeugte Übergabe konnte nicht geschrieben werden (ihr Verzeichnis ist nicht schreibbar, ein Verzeichnis oder eine Datei liegt im Weg, oder die Platte ist voll); die Message nennt die Datei und den Dateisystem-Code, und der Dateisystem-Fehler ist die `cause`.

- **Ausgelöst von**: `export`
- **Nächster Schritt**: Make the output file and its directory writable, then try again.

### LOCALE_STATE_NOT_CARRIED_OVER [#locale_state_not_carried_over]

Geworfen von `editEntry`, `retranslateEntry`, `approveEntry` und `rejectEntry`, die dann nichts schreiben, sonst steht er auf dem `error` einer Locale, die `translate`, `watch` oder `importWorkbook` nicht ausgeführt hat, weil ihr Zustand unter einem umgeschriebenen Code wie `pt_BR` in der Lock-Datei oder der Provenance-Datei nicht zu ihr verschoben werden konnte; der nächste Lauf versucht es erneut ([Ein umgeschriebener Locale-Code](https://verbatra.kreitz-webdev.de/de/docs/the-lock-file.md#ein-umgeschriebener-locale-code)).

- **Ausgelöst von**: `translate`, `watch`, `import`; Studio und der MCP-Server
- **Nächster Schritt**: Wait for other verbatra processes to finish, make verbatra.lock.json and verbatra.provenance.json writable, then try again.

### LOCALE_UNSUPPORTED_BY_PROVIDER [#locale_unsupported_by_provider]

Der konfigurierte Provider DeepL oder Google Cloud Translation führt die Quell-Locale oder eine ausgewählte Ziel-Locale nicht in der Sprachtabelle, die verbatra mitliefert; geworfen von `translate` (auch bei einem Dry-Run und einer Schätzung), `watch` beim Start und `retranslateEntry`, bevor ein Provider gebaut, ein Key gelesen oder eine Locale gestartet wird; einer Locale, die explizit in `localeMap` abgebildet ist, wird stattdessen vertraut ([Sprachunterstützung](https://verbatra.kreitz-webdev.de/de/docs/language-support.md#unterstützung-vor-einem-lauf-prüfen)).

- **Ausgelöst von**: `translate`, `watch`; Studio und der MCP-Server
- **Nächster Schritt**: Remove the unsupported locale from `targetLocales`, map it to a supported code in `provider.options.localeMap`, or choose a provider that supports it.

### NOT_A_LOCALE_FILE [#not_a_locale_file]

`checkFile` hat einen Pfad bekommen, der zu keinem konfigurierten Locale gehört, oder dort gibt es keine Datei.

- **Ausgelöst von**: `check --file`
- **Nächster Schritt**: Pass the path of an existing locale file that `files.pattern` maps to a configured locale.

### SENSITIVE_CONTENT_WITHHELD [#sensitive_content_withheld]

`retranslateEntry` hat den Key nicht gesendet oder seine Antwort verworfen, weil `sensitiveData.mode` auf `block` oder `redact` steht und der Key Inhalt enthält, den ein Detektor oder Muster getroffen hat und der nicht gesendet werden konnte oder nicht unverändert zurückkam ([Schutz für sensible Inhalte](https://verbatra.kreitz-webdev.de/de/docs/data-handling.md#schutz-für-sensible-inhalte)). `translate` und `watch` listen solche Keys stattdessen in `sensitiveWithheld`.

- **Ausgelöst von**: Studio und der MCP-Server
- **Nächster Schritt**: Remove the content from the key, list it in `sensitiveData.allow`, or turn the detector off in `sensitiveData.detectors`.

### RUN_CANCELLED [#run_cancelled]

Das an `translate` oder `retranslateEntry` übergebene `signal` wurde abgebrochen. `retranslateEntry` wirft ihn, wenn der Abbruch kommt, bevor der Provider antwortet, und hat dann nichts geschrieben. `translate` vermerkt ihn auf jeder Locale, die durch den Abbruch nicht mehr startete, und markiert die Zusammenfassung als [`cancelled`](https://verbatra.kreitz-webdev.de/de/docs/sdk/run-summary.md). Ein Einstiegspunkt, der eine Schreibsperre nimmt, etwa `editEntry`, `approveEntry` oder `updateGlossaryTerm`, wirft ihn auch, wenn `releaseHeldLocks` gerade läuft, während er die Sperre nehmen will.

- **Ausgelöst von**: nur das SDK
- **Nächster Schritt**: Run the operation again to finish the work the cancellation left pending.

### LOCALE_FAILED [#locale_failed]

Wird nie geworfen: der Rückfall-`code` auf dem `error` einer fehlgeschlagenen Locale.

- **Ausgelöst von**: `translate`, `watch`, `import`
- **Nächster Schritt**: Fix the cause the locale's message names, then try again.

## Provider-Fehlercodes [#provider-error-codes]

Ein Provider-Fehler wirft einen `ProviderError` mit einem dieser Codes ([Strukturierte Fehler](https://verbatra.kreitz-webdev.de/de/docs/providers.md#strukturierte-fehler)). Innerhalb von `translate` und `watch` scheitert nur seine eigene Anfrage: deren Keys werden zurückgehalten, die Locale bekommt einen Hinweis `SUB_BATCH_FAILED` mit dem Code, und die Keys werden beim nächsten Lauf wieder aufgegriffen. Eine Neuübersetzung eines einzelnen Keys aus Studio oder dem MCP-Server wirft den `ProviderError` weiter. Eine gescheiterte Anfrage endet mit `1`, und ihre Locale endet `partial` oder `failed`.

### MISSING_API_KEY [#missing_api_key]

Die erforderliche Umgebungsvariable ist ungesetzt oder leer. Die Meldung nennt die Variable, nie einen Wert, und in der CLI kommt er als `causeCode` von `PROVIDER_CONSTRUCTION_FAILED` mit Exit-Code `2` an. Bei LibreTranslate, dessen Key optional ist, heißt es, dass der Server einen Key verlangt hat und `LIBRETRANSLATE_API_KEY` nicht gesetzt ist.

- **Nächster Schritt**: Set the API key environment variable your provider reads, then run `verbatra doctor`.

### INVALID_REQUEST [#invalid_request]

Die Anfrage ist vor jedem Netzwerkaufruf an der Validierung gescheitert: ein fehlerhaftes Feld, ein Code, den DeepL nicht akzeptiert (ein `localeMap`-Eintrag mit einem regionalen Quell-Code oder ein Ziel, das auf ein bloßes `en` oder `pt` hinausläuft), oder ein Code, der bei Google Cloud Translation kein wohlgeformtes BCP-47 ist. Bei LibreTranslate deckt es auch eine Sprache ab, für die dein Server kein Modell hat, und eine Anfrage über seinem `--char-limit` oder `--batch-limit`. Wiederholen hilft nicht.

- **Nächster Schritt**: Check the provider options in the config, such as the model name.

### INVALID_RESPONSE [#invalid_response]

Die Ausgabe war fehlerhaft, unvollständig oder scheiterte am Abgleich mit der Anfrage.

- **Nächster Schritt**: Try again; if it keeps failing, configure a different model.

### OUTPUT_TRUNCATED [#output_truncated]

Das Modell hat sein Ausgabe-Token-Limit erreicht; siehe [Ausgabe-Token-Limits](https://verbatra.kreitz-webdev.de/de/docs/providers.md#ausgabe-token-limits).

- **Nächster Schritt**: Translate fewer keys at a time, or configure a model with a larger output limit.

### PROVIDER_REFUSED [#provider_refused]

Das Modell hat die Antwort verweigert.

- **Nächster Schritt**: Review the source text the provider refused, or translate it by hand.

### PROVIDER_BLOCKED [#provider_blocked]

Anfrage oder Antwort wurde aus Sicherheitsgründen blockiert oder gefiltert.

- **Nächster Schritt**: Review the source text the provider blocked, or translate it by hand.

### RATE_LIMITED [#rate_limited]

HTTP 429 oder ein SDK-Rate-Limit-Fehler. Bei Google Cloud Translation gehört hierzu auch ein HTTP 403, dessen Rumpf einen Kontingentgrund nennt (ein Tages- oder Minutenlimit). Google nutzt 403 sowohl für Kontingent- als auch für Zugangsdaten-Fehler, erhöhe also das Cloud-Translation-Kontingent deines Projekts. LibreTranslate meldet ein HTTP 403, dessen Fehlertext "too many" enthält, ebenfalls mit diesem Code, weil sein Server einen gesperrten Client mit 403 beantwortet.

- **Nächster Schritt**: Wait a moment and try again, or lower the concurrency.

### TIMEOUT [#timeout]

Ein Netzwerk- oder Anfrage-Timeout; [`requestTimeoutMs`](https://verbatra.kreitz-webdev.de/de/docs/providers.md#anfrage-timeout) hebt die Grenze an.

- **Nächster Schritt**: Try again, or raise the provider's `requestTimeoutMs` in the config.

### AUTH_FAILED [#auth_failed]

HTTP 401 oder 403: Der Key ist ungültig, widerrufen oder ohne Berechtigung. Bei den Providern Anthropic, OpenAI, Gemini, OpenCode und `openai-compatible` nennt die Meldung den Status und ergänzt bei 403, dass der Server die Anfrage wegen seiner Richtlinie oder der Rechte des Keys abgelehnt hat. Prüfe bei Google Cloud Translation, dass `GOOGLE_TRANSLATE_API_KEY` ein gültiger, uneingeschränkter Key für ein Projekt mit aktivierter Cloud Translation API ist. LibreTranslate meldet außerdem ein HTTP 400, dessen Fehlertext einen API-Key erwähnt, mit diesem Code, wenn ein Key konfiguriert ist. Wiederholen hilft nicht.

- **Nächster Schritt**: Check that the provider's API key is valid and allowed to use the configured model.

### PROVIDER_UNAVAILABLE [#provider_unavailable]

HTTP 5xx: Der Provider ist auf seiner eigenen Seite gescheitert, die Anfrage selbst war nie schuld. Wo ein Provider [wiederholt](https://verbatra.kreitz-webdev.de/de/docs/providers.md#wiederholungen), wird ein vorübergehendes 5xx abgefangen; ein 5xx, das diesen Code erreicht, ist dann eine anhaltende Störung. Google Cloud Translation und LibreTranslate wiederholen nicht, ein einzelnes 5xx landet hier also sofort.

- **Nächster Schritt**: Try again later, or check the configured endpoint.

### NETWORK_POLICY_VIOLATION [#provider-network_policy_violation]

Die [Netzwerkrichtlinie](https://verbatra.kreitz-webdev.de/de/docs/network-policy.md) hat die Anfrage direkt vor dem Senden abgelehnt: Der Hostname löste zu einer Adresse auf, die die Richtlinie nicht erlaubt, oder eine Antwort leitete zu einem abgelehnten Host weiter. Die Meldung nennt nur den Host. Wiederholen hilft nicht.

- **Nächster Schritt**: Point the provider at a host the network policy permits, or add its host to `network.allowedHosts` or VERBATRA_NETWORK_ALLOWED_HOSTS.

### PROVIDER_ERROR [#provider_error]

Alles Unklassifizierbare. Bei den Providern Anthropic, OpenAI, Gemini, OpenCode und `openai-compatible` nennt ein HTTP-Fehlschlag seinen Status, etwa `HTTP 404`, und den Fehlertyp des Servers, wenn er ein kurzes Token aus Buchstaben, Ziffern und Unterstrichen ist, etwa `MissingSessionID`; die eigene Meldung des Servers, der Antworttext und der URL-Pfad erscheinen nie. Bei einer `openai-compatible`-`baseUrl` ergänzt ein 404 oder 405 die Prüfung, ob `baseUrl` die API-Wurzel ist, und ein 400 oder 422 die Prüfung des Modellnamens und der Unterstützung für Chat Completions mit striktem JSON-Schema-Output; bei einem 4xx-Status hilft Wiederholen nicht. Ist der Fehlschlag ein erkennbares Transportproblem, benennt die Meldung es (Verbindung abgelehnt, Hostname nicht aufgelöst, Verbindung geschlossen, Host nicht erreichbar, TLS-Zertifikat nicht verifiziert) und sagt, was zu prüfen ist; sonst fällt sie auf eine statische, geheimnisfreie Meldung zurück. Konnte ein Provider-Paket nicht geladen werden, nennt die Meldung das Paket und rät, `@verbatra/sdk` neu zu installieren.

- **Nächster Schritt**: Act on the cause or HTTP status the message names, then check the provider's `baseUrl` (if it takes one), `model` and the rest of the `provider` block in the config.

## Fehlercodes der Format-Adapter [#adapter-error-codes]

Ein Format-Adapter, der eine Datei nicht verarbeiten kann, wirft einen `AdapterError` mit einem dieser Codes. Bei der Quell-Locale-Datei kommt er eingepackt in `SOURCE_INVALID` an, mit dem Code des Adapters als `causeCode`; bei einer Zieldatei wird er zum `error.code` dieser Locale. Jeder Befehl, der Locale-Dateien liest, Studio und der MCP-Server können ihn auslösen; die CLI endet mit `2`, wenn die Quelldatei schuld ist, und mit `1`, wenn eine Zieldatei ihre Locale in `translate` oder `import` scheitern lässt. `check --file` meldet eine Datei, die sich nicht parsen lässt, stattdessen als `syntax`-Befund. Die Menge ist geschlossen: Ein [eigener Adapter](https://verbatra.kreitz-webdev.de/de/docs/custom-format-adapters.md) wirft einen dieser Codes statt eines eigenen.

### INVALID_JSON [#invalid_json]

Eine JSON-basierte Locale-Datei ist kein gültiges JSON. Die Meldung endet mit Zeile und Spalte, wenn der Parser sie meldet.

- **Nächster Schritt**: Fix the syntax error the message names in that file.

### INVALID_YAML [#invalid_yaml]

Eine YAML-Locale-Datei ist kein gültiges YAML. Die Meldung endet mit Zeile und Spalte, wenn der Parser sie meldet.

- **Nächster Schritt**: Fix the syntax error the message names in that file.

### INVALID_XML [#invalid_xml]

Eine XML-basierte Locale-Datei, etwa XLIFF oder Android-`strings.xml`, ist kein wohlgeformtes XML.

- **Nächster Schritt**: Fix the syntax error the message names in that file.

### INVALID_STRUCTURE [#invalid_structure]

Die Datei lässt sich parsen, hat aber nicht die Form, die das konfigurierte Format erwartet, zum Beispiel ein Key mit Punkten und ein verschachtelter Key-Pfad, die auf denselben Key hinauslaufen, oder ein YAML-Mapping-Key, der eine Map oder eine Sequenz ist.

- **Nächster Schritt**: Reshape the file the message names to match the configured format.

### MAX_DEPTH_EXCEEDED [#max_depth_exceeded]

Die Datei ist tiefer verschachtelt, als verbatra liest.

- **Nächster Schritt**: Reduce the nesting depth of the file the message names.

### INPUT_TOO_LARGE [#input_too_large]

Die Datei ist größer, als verbatra liest.

- **Nächster Schritt**: Split the file the message names into smaller files.

### MIXED_STRUCTURE [#mixed_structure]

Die Datei mischt flache und verschachtelte Keys, wo das Format das verbietet.

- **Nächster Schritt**: Use either flat or nested keys throughout the file the message names.

### ADAPTER_FAILED [#adapter_failed]

Ein `custom:`-Adapter hat einen unerwarteten Fehler geworfen. Der Fehler nennt das Format des Adapters, und der ursprüngliche Fehler des Adapters ist sein `cause`.

- **Ausgelöst von**: das SDK, mit einem `custom:`-Adapter (die CLI lädt kein Plugin)
- **Nächster Schritt**: Report the failure to the maintainer of the custom adapter the message names.

### DUPLICATE_FORMAT [#duplicate_format]

Ein zweiter Adapter wurde für eine Formatkennung registriert, die die Registry schon hält.

- **Ausgelöst von**: `AdapterRegistry.register` im SDK
- **Nächster Schritt**: Register only one adapter for each format identifier.

### INVALID_FORMAT_ID [#invalid_format_id]

Ein Adapter wurde unter einer fehlerhaften `custom:`-Kennung registriert.

- **Ausgelöst von**: `AdapterRegistry.register` im SDK
- **Nächster Schritt**: Name the custom adapter `custom:` followed by a valid name.

## Codes des Review-Gates [#check-result-codes]

`check --require-reviewed` meldet, warum es scheitert, als `result.review.code` ([`verbatra check`](https://verbatra.kreitz-webdev.de/de/docs/cli/check.md)).

### REVIEW_REQUIRED [#review_required]

Mindestens eine maschinell geschriebene Übersetzung (Herkunft `machine`, `memory`, `fuzzy` oder `agent`) ist in der committeten `verbatra.provenance.json` nicht freigegeben. Der Envelope bleibt `ok: true`, und `result.locales[].review.unreviewed` nennt die Keys.

- **Ausgelöst von**: `check --require-reviewed`
- **Exit-Code**: `1`
- **Nächster Schritt**: Gib die genannten Keys in der [Review-Warteschlange von Studio](https://verbatra.kreitz-webdev.de/de/docs/review-in-studio.md) oder mit den MCP-Tools `review.approve` und `review.reject` frei oder korrigiere sie, und committe dann `verbatra.provenance.json`.

### REVIEW_STATE_UNREADABLE [#review_state_unreadable]

`verbatra.provenance.json` ist beschädigt oder stammt von einem neueren verbatra, also lässt sich kein Review-Stand lesen, und das Gate schlägt sicherheitshalber fehl.

- **Ausgelöst von**: `check --require-reviewed`
- **Exit-Code**: `1`
- **Nächster Schritt**: Stelle `verbatra.provenance.json` aus der Versionskontrolle wieder her, oder aktualisiere verbatra, wenn eine neuere Version die Datei geschrieben hat.

## Gründe für Integritätsablehnungen [#integrity-refusal-reasons]

Das [Integritäts-Gate](https://verbatra.kreitz-webdev.de/de/docs/translation-safety.md#das-integritäts-gate) lehnt einen Kandidatenwert mit genau einem dieser Gründe ab, dem ersten, der in der dort genannten Reihenfolge zutrifft. Der Grund steht nach `translate`, `watch` und `import` in den `integrityRefusals` einer Locale (`integrity-withheld` in der Ausgabe für Menschen), im Ergebnis von `editEntry` und von `retranslateEntry` (`accepted: false` mit dem `reason`) und als Fehler von `check --qa`, oft mit `details`, die nennen, was abweicht. Eine Ablehnung endet mit `1` bei `check --qa` und bei `translate` und `import`, wenn die Locale partial oder failed endet. Die Menge wird als Tupel `INTEGRITY_GATE_REASONS` ausgeliefert.

### placeholder [#placeholder]

Die Platzhalter des Kandidaten weichen von denen seiner Quelle ab, verglichen als Multimenge: Die Anzahl zählt, die Reihenfolge nicht. Was als Platzhalter gilt, legt jedes [Format](https://verbatra.kreitz-webdev.de/de/docs/formats.md) fest. Bei i18next, ngx-translate und YAML wird auch ein Token der Form `{name}` abgelehnt, das der Kandidat hinzufügt und die Quelle nie hatte, obwohl einfache geschweifte Klammern dort wörtlicher Text sind. Die Details nennen jeden weggelassenen Platzhalter mit `-` und jeden hinzugefügten mit `+`, etwa `-{{name}}` oder `+{{nom}}`.

- **Nächster Schritt**: Setze die Platzhalter der Quelle wieder in die Übersetzung ein oder lass den nächsten Lauf sie neu übersetzen.

### markup [#markup]

Das Inline-HTML- oder -XML-Markup des Kandidaten weicht von dem seiner Quelle ab oder ist nicht wohlgeformt. Die Details nennen jedes Tag hinter der Ablehnung, mit `-` für eines, das die Quelle hatte und der Kandidat weggelassen hat, oder mit `+` für eines, das der Kandidat erfunden hat.

- **Nächster Schritt**: Behalte die Tags, Attributnamen und geschützten Attributwerte der Quelle in der Übersetzung bei.

#### Wie Markup verglichen wird [#wie-markup-verglichen-wird]

Tags werden als Multimenge aus Tag-Namen plus Attributnamen verglichen:

- Abgelehnt: ein weggelassenes Tag, ein erfundenes Tag, ein umbenanntes Tag, ein geänderter Satz von
  Attributnamen (auch ein ergänztes `dir`-Attribut für ein Ziel mit Schreibrichtung von rechts nach
  links), Markup, das unausgeglichen oder falsch verschachtelt zurückkommt, etwa
  `<b>a<i>b</b></i>`, sowie ein Tag, das in einem anderen gleichen Namens verschachtelt zurückkommt,
  obwohl die Quelle sie nebeneinander hatte, denn so werden aus zwei Links still und leise einer.
- Akzeptiert: dieselben Tags in anderer Reihenfolge, ein geänderter Attributwert wie ein übersetztes
  `title` oder ein lokalisiertes `href` (innerhalb der weiter unten beschriebenen
  Grenzen für Attributwerte), und beide Schreibweisen eines leeren Elements, `<br>` und `<br/>` sind
  dasselbe Tag.
- Gezählt, nicht nur bemerkt: zwei benachbarte Paare, die zu einem verschmolzen werden
  (`<b>a</b> <b>b</b>` wird `<b>a b</b>`), werden abgelehnt.
- Exakt verglichen: Eine Änderung der Groß- und Kleinschreibung ist ein Befund. Die leeren
  HTML-Elemente (`<br>`, `<img>`, `<hr>` und die übrigen) brauchen in jeder Schreibweise kein
  schließendes Tag, `<BR>` wird also genauso als leeres Element erkannt wie `<br>`.

Auch eine Quelle ganz ohne Markup ist gegen hineinerfundenes Markup geschützt. Der Kandidat wird
abgelehnt für jedes Tag-Paar, jedes leere Element und jedes selbstschließende Tag, das er ergänzt,
für ein schließendes Tag ohne öffnendes (`Hallo</div>`) und für ein nie geschlossenes öffnendes
Tag, das mehr als seinen Namen trägt, etwa `<Enter onfocus=...>` oder `<x-key onmouseover=...>`.

Ein nie geschlossenes `<Word>`, das nur aus seinem Namen besteht und dessen Name nur Buchstaben,
Ziffern, Bindestriche und Unterstriche enthält, ist ein Wort in spitzen Klammern, etwa `<Enter>` in
`Druecke <Enter>`. Solche Wörter werden auf beiden Seiten beiseitegelegt, bevor die Quelle beurteilt
wird, eine Quelle mit einem solchen Wort wird also trotzdem verglichen: Ein Kandidat, der neben
`<Enter>` ein `<b>`-Paar weglässt oder ein `<script>`-Paar erfindet, wird abgelehnt. Sobald die
Quelle Tags trägt, werden Wörter in spitzen Klammern wie Tags gezählt. Trägt sie keine, gilt ein
Wort in spitzen Klammern, das der Kandidat ergänzt, als normaler Text und wird angenommen, es sei
denn, sein Name ist in beliebiger Schreibweise ein Standard-HTML-Element (`Hallo <script>`), lautet
`image`, woraus ein Parser ein `<img>` macht, oder enthält einen Bindestrich, was ihn zu einem
Custom Element macht (`Hallo <my-widget>`).

Dieser Namenstest ist bewusst vorsichtig: Ein gewöhnliches Wort, das zufällig ein Elementname ist,
etwa `<Del>`, `<Option>`, `<Select>`, `<Input>` oder `<Menu>`, wird abgelehnt, wenn eine Übersetzung
es zu einer Quelle hinzufügt, die es nicht hat. Als Ausweg behältst du das Wort in spitzen Klammern
auch in deinem Quellstring: Eine Übersetzung, die dieselben Wörter in spitzen Klammern trägt wie ihre
Quelle, wird angenommen.

Kommentare, CDATA-Abschnitte, Deklarationen und Verarbeitungsanweisungen sind keine Tags, und sie
werden so gelesen, wie ein HTML-Parser sie liest. `<!-->` und
`<!--->` sind vollständige leere Kommentare, ein Kommentar endet beim ersten `-->` oder `--!>`, und
ein Kommentar ohne Ende verbirgt den Rest des Werts. `<![CDATA[`, `<!DOCTYPE html>`, jedes andere
`<!...`, `<?...` und ein `</`, auf das etwas anderes als ein Buchstabe folgt, etwa `</1 x>`, enden
alle beim ersten `>`, während ein leeres `</>` wegfällt, so wie ein Parser es verwirft, und ein
numerisches schließendes Tag wie `</0>` als Tag verglichen wird. Jedes solche Konstrukt wird als
Multimenge seines Texts verglichen, wobei Folgen von Leerraum zusammengefasst werden, eines, das der
Kandidat ergänzt, weglässt oder umschreibt, wird also abgelehnt, auch ein Kommentar, dessen Text
übersetzt wurde. Tags nach dem Ende eines Konstrukts werden wie gewohnt verglichen,
`Hallo <![CDATA[><img src=x onerror=...>]]>` wird also sowohl für das Konstrukt als auch für das
`<img>` abgelehnt.

Auch der Inhalt eines Raw-Text-Elements ist Text. Nach einem öffnenden
`script`-, `style`-, `title`-, `textarea`-, `xmp`-, `iframe`-, `noscript`-, `noembed`- oder
`noframes`-Tag ist alles bis zu seinem schließenden Tag Text, in beliebiger Schreibweise und gefolgt
von Leerraum, `/` oder `>`, und nach `<plaintext>` ist alles bis zum Ende des Werts Text. Ein Tag,
das in einem solchen Element steht, wird nicht verglichen, und ein Attributwert in Anführungszeichen
kann nicht über das schließende Tag hinwegreichen, um zu verbergen, was folgt:
`Füge ein <script><b x="</script><img src=x onerror=...>` wird für das `<img>` abgelehnt. Wo ein
Parser diesen Inhalt auf zwei Arten lesen kann, wird der Kandidat abgelehnt, es sei denn, er ist die
unveränderte Quelle, mit einem Detail wie `+<noscript>...</noscript>`: ein `script`, dessen Inhalt
`<!--` öffnet, ein `noscript`, dessen Inhalt ein `<` enthält, weil dann davon abhängt, ob Skripte
aktiviert sind, wie er gelesen wird, und jedes Raw-Text-Element, dessen Inhalt nach einem `svg`-,
`math`- oder `select`-Tag ein `<` enthält, denn dort ist es womöglich gar kein Raw Text. Aus
demselben Grund wird ein CDATA-Abschnitt oder ein `image`-Tag in einem Wert, in dem die Quelle oder
der Kandidat `svg`, `math` oder `select` öffnet, abgelehnt, es sei denn, der Kandidat ist die
unveränderte Quelle.

Der Inhalt eines `script`-, `style`-, `iframe`-, `noembed`-, `noframes`-, `noscript`-, `xmp`- oder
`plaintext`-Elements wird ausgeführt oder gestaltet die Seite, statt angezeigt zu werden, und wird
deshalb nie übersetzt: Jedes solche Element im Kandidaten muss genau den Inhalt des Elements
tragen, das in der Quelle an derselben Position unter den Elementen dieses Namens steht, sonst wird
der Kandidat mit einem Detail wie `+<script> content` abgelehnt. Der Inhalt von `title` und
`textarea` wird als Text angezeigt und darf übersetzt werden. Damit ist normaler Text, der eines dieser Tags wörtlich
enthält, nicht übersetzbar, denn in `Add a <script> tag` ist alles nach `<script>` sein Inhalt:
`Füge ein <script> Tag` wird abgelehnt. Maskiere das Tag stattdessen in der Quelle, als
`Add a &lt;script&gt; tag`.

Die Prüfung ist bewusst zurückhaltend, liest Tags aber so, wie ein HTML-Parser es tut. Ein Tag
beginnt bei `<` oder `</`, gefolgt von einem Buchstaben oder, bei einem numerischen Rich-Text-Tag
wie `<0>`, von Ziffern. Sein Name reicht bis zu Leerraum, `/` oder `>`, und ein Attributwert in
Anführungszeichen darf `>` enthalten. `5 < 10`, `x <= y` und ein maskiertes `&lt;b&gt;` bleiben also
normaler Text, während `<support@example.com>` und `<abbr title="a > b">` Tags sind, und ein `<`,
das sein `>` nie erreicht, stellt nichts dar und ist kein Tag. Ein Kandidat, der ein Tag auf diese
Weise unvollendet lässt, wird trotzdem abgelehnt, wenn seine Quelle jedes Tag vollendet, mit einem
Detail, das den unvollendeten Anfang nennt, etwa `+<a`. Eine Quelle, deren eigene Tags fehlerhaft
sind, wird trotzdem verglichen. Nachdem die Tags, die das Format als Platzhalter meldet, und alle
Wörter in spitzen Klammern beiseitegelegt sind, gilt eine Quelle als fehlerhaft, wenn sie ein
öffnendes Tag hat, das nie geschlossen wird (leere Elemente ausgenommen), ein schließendes Tag ohne
öffnendes oder Tags, die in falscher Reihenfolge geschlossen werden. Normaler Text kann das
versehentlich auslösen: In `a<b and c>d` ist `<b and c>` ein öffnendes `b`-Tag mit den Attributen
`and` und `c`, das nie geschlossen wird, die Quelle gilt also als fehlerhaft. Bei einer solchen
Quelle entfällt nur die Prüfung der Verschachtelung: ihre Tags werden wie alle anderen als
Multimenge verglichen, eine Übersetzung, die `a<b and c>d` exakt beibehält, wird also angenommen,
eine, die daneben ein `<img>` ergänzt, abgelehnt, und ebenso eine, die die Wörter innerhalb der
Folge übersetzt (`a<b und c>d`), weil ein Parser `und` als neues Attribut liest. Auch ist keine
Quelle zu groß für den Vergleich. Ein Kandidat wird erst abgelehnt, wenn er mehr als doppelt so
viele Tags und Konstrukte trägt wie seine Quelle, bei einer kleineren Quelle mehr als 256, mit dem
Detail `+more than N inline tags`, das diese Grenze nennt.

Attributwerte sind frei, mit diesen Ausnahmen. Der Wert eines URL-Attributs (`href`, `src`, `action`, `formaction`, `xlink:href`, `poster`,
`data`, `background`, `ping`, `cite`, `longdesc`, `srcset`, `manifest`, `codebase`, `archive` sowie
die SVG-Animationsattribute `to`, `from`, `values` und `by`) wird gelesen, nachdem numerische
Zeichenreferenzen sowie `&colon;`, `&Tab;`, `&NewLine;`, `&sol;` und `&bsol;` dekodiert und Tabs,
Zeilenumbrüche und umgebende Steuerzeichen ignoriert wurden. Ein `javascript:`-, `vbscript:`- oder
`data:`-Schema darin wird abgelehnt, es sei denn, die Quelle trägt genau diesen Wert am selben Tag
und Attribut, mit einem Detail wie `+<a href="javascript:...">`. Darüber hinaus muss jede URL im Wert,
auch jede URL einer `srcset`-, `ping`-, `archive`- oder `values`-Liste, ein Schema und eine
Authority (Host und Port oder den Host einer schemarelativen `//host`-URL) behalten, die ein
Quellwert desselben Tags und Attributs hat, und eine relative URL muss relativ bleiben. `/docs` darf
also zu `/de/docs` werden und `https://verbatra.dev/en` zu `https://verbatra.dev/de`, aber `/docs`
darf nicht zu `https://evil.example/docs` oder `//evil.example/docs` werden, und ein lokalisierter
absoluter Link muss denselben Host behalten; das Detail nennt den neuen Origin, etwa
`+<a href="https://evil.example...">`, oder `+<a href="./...">` für einen absoluten Link, der
relativ gemacht wurde. Pfad, Query und Fragment dürfen sich frei ändern. Eine geänderte URL ohne
explizites Schema `http`, `https`, `ws`, `wss`, `ftp` oder `file` wird außerdem abgelehnt, wenn ein
Backslash (`\` oder `%5C`) in ihren führenden Schrägstrichen oder ihrem Host steht, denn eine Seite
mit einem anderen Schema liest `//verbatra.dev\@evil.example/` als Link auf evil.example.

Manche Attributwerte müssen genau so zurückkommen, wie die Quelle sie hat, verglichen nach dem
Dekodieren von Zeichenreferenzen, mit einem Detail wie `+<meta content="...">`: `http-equiv` und
`content` an `meta`; `type`, `nomodule`, `integrity` und `crossorigin` an `script`; `rel`, `as`,
`integrity`, `crossorigin` und `type` an `link`; `target` an `base`; `attributeName` und
`attributeType` an `set`, `animate`, `animateTransform` und `animateMotion`; `sandbox`, `allow` und
`allowfullscreen` an `iframe`; `method`, `enctype` und `target` an `form`; sowie `style`, `srcdoc`
und jeder Event-Handler wie `onclick` an jedem Element. Ein übersetzbares Attribut wie `title` oder
`alt` bleibt frei.

Aus dem Vergleich ganzer Werte folgen zwei formatbedingte Grenzen. Bei einem Format, das mehrere
Pluralformen durch einen senkrechten Strich getrennt in einen Wert packt (Vue I18n), wiederholt eine
Übersetzung, die die Formen ihrer Sprache ergänzt, das Markup der Quelle und wird abgelehnt.
Dasselbe passiert bei einem Plural im ICU-Stil (`{count, plural, one {...} other {...}}`) in einem
Format, das ihn als reinen Text speichert, statt ihn als ICU zu parsen (i18next, ngx-translate und
YAML): Eine Übersetzung mit einer anderen Zahl von Formen als die Quelle wiederholt das Markup darin
oder lässt es weg und wird abgelehnt. In beiden Fällen bleibt die bisherige Übersetzung.

Die Prüfung tritt außerdem pro Tag zurück. Ein Tag, das das Format ohnehin als Platzhalter meldet
(ein XLIFF-Inline-Element, ein ICU-Rich-Text-Tag von next-intl oder ARB), bleibt zusammen mit so
vielen schließenden Tags, wie es öffnende gibt, der Platzhalterprüfung überlassen und wird nie
doppelt gemeldet. Ein solches öffnendes Tag, das der Kandidat nie schließt, wird trotzdem abgelehnt
und über das fehlende schließende Tag benannt, etwa `-</g>`. Ebenso eines, dessen Verschachtelung
mit den übrigen Tags nicht mehr der Quelle entspricht, etwa ein `<b>`, das das `<g>`, in dem es
stand, jetzt kreuzt, und eines, das die Quelle nur als Text trägt, in einem Kommentar oder einem
Raw-Text-Element, weil es herausgezogen das Element erzeugen würde. Jedes andere Tag im selben Wert
wird weiterhin verglichen, auch ein überzähliges schließendes Tag wie ein zweites `</g>`.

### icu [#icu]

Bei next-intl und ARB lässt sich der Kandidat nicht mehr als ICU-Nachricht parsen (auch ein `plural` ohne seinen `other`-Zweig), oder seine `plural`- oder `selectordinal`-Zweige passen nicht zu den CLDR-Kategorien der Zielsprache, oder seine `select`-Zweige weichen von denen der Quelle ab. Die Details nennen jeden falschen Zweig. [Plural-Zweige je Zielsprache](https://verbatra.kreitz-webdev.de/de/docs/translation-safety.md#plural-zweige-je-zielsprache) erklärt die Regel.

- **Nächster Schritt**: Korrigiere die Nachricht, sodass sie sich parsen lässt und genau die Zweige trägt, die die Zielsprache braucht.

### degenerate [#degenerate]

Der Kandidat ist strukturell entartet: eine Wiederholungsschleife oder eine Länge, die sich von der Quelle entfernt hat. So sieht ein Modell aus, das in die Wiederholung eines Fragments gekippt ist, auch wenn jeder Platzhalter überlebt hat.

- **Nächster Schritt**: Lass den nächsten Lauf den Key neu übersetzen oder schreib die Übersetzung von Hand.

### empty [#empty]

Der Kandidat ist leer oder besteht nur aus Leerraum, obwohl seine Quelle es nicht ist. Eine Übersetzung zu leeren ist ein bewusster Schritt: Das macht der Platzhalter `[[CLEAR]]` der Arbeitsmappe.

- **Nächster Schritt**: Schreib eine Übersetzung oder leere den Wert bewusst mit `[[CLEAR]]` in einem Arbeitsmappen-Import.

## Review-Gründe [#review-reason-codes]

Ein Review-Flag markiert eine angenommene Übersetzung als einen zweiten Blick wert; es hält nie einen Key zurück, und eine Warnung von `check --qa` lässt den Job nur mit `--strict` scheitern. Die Menge wird als Tupel `REVIEW_REASON_CODES` ausgeliefert; [Übersetzungssicherheit](https://verbatra.kreitz-webdev.de/de/docs/translation-safety.md#review-flags) erklärt die Review-Schicht.

### LENGTH_RATIO_OUTLIER [#length_ratio_outlier]

Die Übersetzung ist viel kürzer oder länger als ihre Quelle.

Er greift unter dem 0.35-Fachen oder über dem 3.0-Fachen der getrimmten Quelllänge; sehr kurze Quellen werden übersprungen. Gezählt wird in Graphem-Clustern, und jedes Zeichen wird nach seiner Schrift gewichtet: Ein chinesisches Zeichen zählt 3.5, ein japanisches Kana 1.5 und eine koreanische Silbe 2.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Lies die Übersetzung gegen ihre Quelle, dann behalte oder korrigiere sie.

### MAX_LENGTH_EXCEEDED [#max_length_exceeded]

Die Übersetzung ist länger als das für ihren Key konfigurierte `maxLength`-Budget.

Gezählt wird in Graphem-Clustern, am Wert genau so, wie er geschrieben ist. Die Grenze ist inklusiv, ein Wert von genau der Budgethöhe wird also nicht markiert, und ein Key ohne Budget wird nie gemessen.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Kürze die Übersetzung, oder hebe das `maxLength`-Budget des Keys an.

### EQUALS_SOURCE [#equals_source]

Die Übersetzung gleicht ihrer Quelle wörtlich, obwohl die Ziel-Locale eine andere ist.

Er greift nur, wenn die Quelle übersetzbaren Text hat: Eine Quelle, die nur aus `doNotTranslate`-Begriffen besteht oder aus Begriffen, deren Übersetzung der Begriff selbst ist, wird nicht markiert.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Übersetze den Wert, oder behalte ihn, wenn der Text in dieser Sprache wirklich gleich bleibt.

### GLOSSARY_TERM_MISSED [#glossary_term_missed]

Einem Glossarbegriff aus der Quelle fehlt seine Übersetzung für die Ziel-Locale, oder ein `doNotTranslate`-Begriff fehlt oder wurde verändert.

Jede Locale wird gegen ihre eigene Übersetzung des Begriffs aus einem Glossar pro Locale geprüft. Der Abgleich ignoriert Groß- und Kleinschreibung, außer der Begriff ist `caseSensitive`, und richtet sich dabei nach den Regeln der jeweiligen Locale (auch beim türkischen `İ`). Die Quellseite verlangt ein ganzes Wort, `AI` wird also in `Airport` nicht gefunden; die Zielseite verlangt nur, dass der Begriff irgendwo im Wert steht, weil ein übersetzter Begriff mit seinem Umfeld verschmilzt. Ein Begriff in einer Schrift ohne Worttrenner (Han, Kana, Thai und ähnliche) wird als bloßes Enthaltensein abgeglichen.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Verwende die Übersetzung des Begriffs aus dem Glossar, oder lass den Begriff unverändert.

### GLOSSARY_FORBIDDEN_TERM [#glossary_forbidden_term]

Die Übersetzung verwendet eine Wiedergabe, die die `forbidden`-Liste des Glossars für die Ziel-Locale ausschließt.

Abgeglichen wird als ganzes Wort, bei Schriften ohne Worttrenner als bloßes Enthaltensein, eine gebeugte oder zusammengesetzte Form wird also nur erkannt, wenn du sie ebenfalls auflistest. Eine Wiedergabe, die schon in der Quelle steht, wird nicht markiert, weil die Übersetzung sie zitieren darf.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Ersetze die verbotene Wiedergabe durch die freigegebene.

### INTEGRITY_REORDERED [#integrity_reordered]

Die Platzhalter stimmen genau überein, stehen aber in einer anderen Reihenfolge als in der Quelle.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Prüfe, ob sich die neue Reihenfolge in der Zielsprache richtig liest.

### PROVIDER_DEGRADED [#provider_degraded]

Der Provider hat den Batch, aus dem dieser Key stammt, herabgestuft, etwa durch eine heruntergestufte Formalität oder ein ignoriertes Glossar.

Er greift, wenn der Batch einen Hinweis `FORMALITY_DOWNGRADED` oder `GLOSSARY_IGNORED` trug, wie ihn DeepL, Google Cloud Translation und LibreTranslate melden. `PLACEHOLDER_UNSUPPORTED` löst ihn nicht aus, weil diese Einträge zurückgehalten und nicht herabgestuft werden.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`)
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe den Ton und die Glossarbegriffe des Werts.

### FUZZY_CACHE_REUSE [#fuzzy_cache_reuse]

Der Wert wurde aus dem Cache für eine frühere, fast gleiche Quelle wiederverwendet, die seitdem bearbeitet wurde. Das kommt nur mit aktiviertem `fuzzyCache` vor.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`)
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe, ob der wiederverwendete Wert noch zur bearbeiteten Quelle passt.

### FOREIGN_PLACEHOLDER_CHANGED [#foreign_placeholder_changed]

Die Übersetzung hat ein Token verloren oder verändert, das wie ein Platzhalter aussieht, den das Format des Projekts nicht interpoliert, etwa `{name}` in einem i18next-Wert oder `%{count}` in einem YAML-Wert.

Er greift, wenn ein solches Token in der Quelle öfter vorkommt als, wörtlich, in der Übersetzung. Die eigenen Platzhalter des Formats prüft das Integritäts-Gate, ein Token, das die Übersetzung nur hinzufügt, wird nicht markiert, und ein ICU-Argument zählt einmal, über seinen Kopf wie `{n, plural,`, sodass übersetzte Zweige ihn nie auslösen. Tokens in ICU-Zweigen, ein printf-Token direkt an einem Buchstaben oder einer Ziffer, prozentkodierte Bytes wie `%2F` und alles in einer URL werden nie geprüft, ebenso wenig Formate aus Adaptern von Drittanbietern. Welche Syntax jedes Format schützt, steht unter [Formate](https://verbatra.kreitz-webdev.de/de/docs/formats.md).

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung, die jedes fehlende Token in `details` nennt, etwa `-{name}`)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Stelle das Token in der Übersetzung wieder her, wenn deine Bibliothek es interpoliert.

### BIDI_CONTROLS_CHANGED [#bidi_controls_changed]

Die Übersetzung enthält unsichtbare Richtungssteuerzeichen, die den Text um sie herum umordnen können: eine Einbettung, Überschreibung oder Isolierung, die sie nie schließt, oder eine Überschreibung, die die Quelle nicht hat.

Er greift, wenn die Einbettungen (U+202A, U+202B), Überschreibungen (U+202D, U+202E) und Isolierungen (U+2066 bis U+2068) der Übersetzung innerhalb eines Absatzes nicht zu ihren Abschlusszeichen (U+202C, U+2069) passen, die der Quelle aber schon, oder wenn sie mehr Links-nach-rechts- oder Rechts-nach-links-Überschreibungen enthält als die Quelle. Ein offenes Steuerzeichen überträgt seine Richtung auf den Text, den deine App hinter den Wert setzt. Richtungsmarken wie U+200F lösen ihn nie aus, ebenso wenig eine Übersetzung, die ausgeglichene Steuerzeichen der Quelle weglässt.

- **Ausgelöst von**: `translate`, `watch` (in `needsReview`); `retranslateEntry` (in `reviewReasons`); `export` (in der Review-Spalte); `check --qa` (als Warnung)
- **Exit-Code**: keiner aus `translate`; `1` aus `check --qa --strict`
- **Nächster Schritt**: Schließe oder entferne die Richtungssteuerzeichen in der Übersetzung.

## Laufhinweise [#sdk-notice-codes]

Ein Hinweis steht als Daten in den `notices` einer Locale und wird nie geworfen. Er meldet einen Zustand, den der Lauf behandelt hat, und ändert den Exit-Code nur dort, wo der Eintrag es sagt. [RunSummary](https://verbatra.kreitz-webdev.de/de/docs/sdk/run-summary.md) zeigt, wo Hinweise in der Zusammenfassung stehen.

### PLURAL_CATEGORIES_INCOMPLETE [#plural_categories_incomplete]

Einem Plural in einer Ziel-Locale fehlt eine CLDR-Pluralkategorie, die seine Sprache verwendet, etwa ein polnischer Plural mit nur `one` und `other`, und verbatra konnte den Rest nicht erzeugen.

- **Ausgelöst von**: `translate`, `watch`; `check` führt ihn bei den Pluralen auf, `doctor` unter Plural completeness
- **Exit-Code**: keiner für sich allein; `1` aus `check --qa --strict`
- **Nächster Schritt**: Ergänze die fehlenden Pluralformen von Hand.

### SUB_BATCH_FAILED [#sub_batch_failed]

Eine Provider-Anfrage ist gescheitert. Der Hinweis nennt den Fehlercode des Providers, oder `PROVIDER_CALL_FAILED`, wenn der Fehler kein strukturierter Provider-Fehler war, und die Keys der Anfrage stehen unter `providerFailures`. Sein `causeCode` trägt den Code des Providers, wenn es einen gibt, und die CLI gibt nach dem Lauf den nächsten Schritt zu diesem Code aus.

- **Ausgelöst von**: `translate`, `watch`
- **Exit-Code**: `1`: die Locale endet `partial` oder `failed`
- **Nächster Schritt**: Schlag den genannten Code unter [Provider-Fehlercodes](#provider-error-codes) nach. Die Keys werden beim nächsten Lauf erneut übersetzt.

### BLANK_ROW_BASELINE_RETAINED [#blank_row_baseline_retained]

Eine importierte Zeile blieb leer für einen Key, dessen Quelle sich seit der Baseline der Zeile geändert hat, also wurde die alte Baseline behalten, und der Drift wird weiter gemeldet.

- **Ausgelöst von**: `import`
- **Exit-Code**: keiner für sich allein
- **Nächster Schritt**: Übersetze den Key in einem neuen Export, oder führe `verbatra translate` aus.

### HANDOFF_REVIEWS_RECORDED [#handoff_reviews_recorded]

Eine XLIFF-Übergabe hat Keys als geprüft oder final markiert, und sie wurden in `verbatra.provenance.json` als freigegeben festgehalten.

- **Ausgelöst von**: `import`
- **Exit-Code**: keiner
- **Nächster Schritt**: Nichts zu beheben; committe `verbatra.provenance.json`.

### BUDGET_TOKENS_EXCEEDED [#budget_tokens_exceeded]

Der Lauf hat sein Token-Budget erreicht: `maxTokens` in der Konfiguration oder `--max-tokens` für einen Lauf. Unter `"warn"` läuft er weiter; unter `"stop"` werden die noch nicht versuchten Keys zurückgehalten und unter `budgetWithheld` aufgeführt.

- **Ausgelöst von**: `translate`, `watch`
- **Exit-Code**: keiner unter `budgetBehavior: "warn"`; `1` unter `"stop"`, sobald Keys zurückgehalten werden
- **Nächster Schritt**: Hebe das Budget an, oder starte erneut: Zurückgehaltene Keys werden beim nächsten Lauf übersetzt.

### CACHE_VERSION_UNRECOGNIZED [#cache_version_unrecognized]

`verbatra.cache.json` wurde von einem neueren verbatra geschrieben, also blieb die Datei unberührt, und der Lauf hat keinen Cache verwendet.

- **Ausgelöst von**: `translate`, `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Aktualisiere verbatra, oder lösch die Datei, damit sie neu aufgebaut wird.

### PROVENANCE_VERSION_UNRECOGNIZED [#provenance_version_unrecognized]

`verbatra.provenance.json` wurde von einem neueren verbatra geschrieben, also blieb die Datei unberührt, und der Lauf hat für die geschriebenen Werte keine Herkunft festgehalten.

- **Ausgelöst von**: `translate`, `watch`, `import`
- **Exit-Code**: keiner
- **Nächster Schritt**: Aktualisiere verbatra, damit die Aufzeichnung aktuell bleibt.

### PROVENANCE_FILE_TOO_LARGE [#provenance_file_too_large]

Das Festhalten dieser Locale hätte `verbatra.provenance.json` über die Größe wachsen lassen, die verbatra zurückliest, also blieb die Datei, wie sie war, und die Werte der Locale haben keinen Eintrag.

- **Ausgelöst von**: `translate`, `watch`, `import`
- **Exit-Code**: keiner
- **Nächster Schritt**: Die Werte bleiben geschrieben; nur ihr Eintrag fehlt. Prüf vor dem nächsten Lauf, warum die Datei so groß geworden ist.

### LOCALE_STATE_CARRIED_OVER [#locale_state_carried_over]

Unter einer Schreibweise mit Unterstrich wie `pt_BR` festgehaltener Stand wurde zum konfigurierten `pt-BR` verschoben. Siehe [Ein umgeschriebener Locale-Code](https://verbatra.kreitz-webdev.de/de/docs/the-lock-file.md#ein-umgeschriebener-locale-code).

- **Ausgelöst von**: `translate`, `watch`, `import`
- **Exit-Code**: keiner
- **Nächster Schritt**: Nichts zu beheben; committe die Lock- und die Provenance-Datei.

### LOCALE_STATE_CARRY_OVER_SKIPPED [#locale_state_carry_over_skipped]

Dieses Verschieben wurde auf den nächsten Lauf verschoben, weil die Sperre der Lock-Datei belegt blieb oder nicht gelesen oder angelegt werden konnte, oder weil eine Datei nicht geschrieben werden konnte. Sofern nicht nur der Übersetzungsspeicher zurückblieb, lief die Locale nicht und scheiterte mit `LOCALE_STATE_NOT_CARRIED_OVER`.

- **Ausgelöst von**: `translate`, `watch`, `import`
- **Exit-Code**: `1`, wenn die Locale mit `LOCALE_STATE_NOT_CARRIED_OVER` gescheitert ist
- **Nächster Schritt**: Warte, bis andere verbatra-Prozesse fertig sind, und starte dann erneut.

### LOCALE_UNVERIFIED_BY_PROVIDER [#locale_unverified_by_provider]

Der gesendete Code steht nicht in der Sprachtabelle des Providers: Nur seine Basissprache steht dort, oder er stammt aus `localeMap`.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`; `doctor --locales` meldet ihn
- **Exit-Code**: keiner
- **Nächster Schritt**: Führe `verbatra doctor --locales` aus, um den gesendeten Code zu sehen, und bilde die Locale in `provider.options.localeMap` ab, wenn er falsch ist.

### LOCALE_NOT_WELL_TESTED [#locale_not_well_tested]

Ein LLM-Provider übersetzt in eine Sprache außerhalb der Liste gut getesteter Sprachen.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`; `doctor --locales` meldet ihn
- **Exit-Code**: keiner
- **Nächster Schritt**: Lass die Übersetzungen für diese Locale von einem Menschen prüfen.

### GLOSSARY_UNSUPPORTED_BY_PROVIDER [#glossary_unsupported_by_provider]

Der Provider kann für diese Locale kein Glossar anwenden.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`; `doctor --locales` meldet ihn
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe die Glossarbegriffe im Review, oder wähle einen Provider, der für die Locale ein Glossar anwendet.

### FORMALITY_UNSUPPORTED_BY_PROVIDER [#formality_unsupported_by_provider]

Der Provider kann den konfigurierten Ton für diese Locale nicht anwenden.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`; `doctor --locales` meldet ihn
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe den Ton im Review, oder wähle einen Provider, der für die Locale Formalität anwendet.

### SOURCE_FOREIGN_PLACEHOLDERS [#source_foreign_placeholders]

Quellwerte, die diese Locale gleich übersetzt, enthalten ein Token, das wie ein Platzhalter aussieht, den das Format des Projekts nicht interpoliert. Die Meldung nennt die Zahl solcher Werte und die ersten Keys.

DeepL, Google Cloud Translation und LibreTranslate bekommen ein solches Token wie einen Platzhalter maskiert und halten einen Wert zurück, den sie nicht maskieren oder wiederherstellen können ([`PLACEHOLDER_UNSUPPORTED`](#placeholder_unsupported)). Ein LLM-Provider oder ein Mensch muss es unverändert lassen; eine Übersetzung, die es verliert oder verändert, wird mit [`FOREIGN_PLACEHOLDER_CHANGED`](#foreign_placeholder_changed) markiert. Der Hinweis kommt pro Locale, nur wenn diese Locale einen solchen Key zu übersetzen hat, und nie für Formate aus Adaptern von Drittanbietern.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe die Übersetzungen der genannten Keys, oder wechsle die Syntax, wenn deine Bibliothek diese Tokens nicht interpoliert.

### SOURCE_VALUE_EMPTY [#source_value_empty]

Quell-Keys, deren Wert leer ist oder nur aus Leerraum besteht, etwa ein Key, den [`extract`](https://verbatra.kreitz-webdev.de/de/docs/cli/extract.md) ohne Standardwert ergänzt hat, sind nie fehlend, veraltet oder aktuell, egal was Ziel oder Lock-Datei enthalten; in einem `gettext-po`-Quellkatalog ist das ein leerer `msgstr`. Für sie wird nichts gesendet, geschrieben oder gezählt, und das Ziel behält den Wert, den es hat. Die Meldung nennt die Zahl der Keys und die ersten davon.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Schreib den Quelltext der genannten Keys und lass dann `verbatra translate` erneut laufen.

### SENSITIVE_CONTENT_SENT [#sensitive_content_sent]

Unter `sensitiveData.mode: "warn"` enthalten Keys oder Glossarbegriffe, die diese Locale gesendet hat, Inhalt, den ein Detektor oder Muster getroffen hat. Sie wurden unverändert gesendet. Die Meldung nennt die Detektoren und die ersten Keys, nie den gefundenen Text, außer er steht im Key-Namen.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Entferne den Inhalt, erlaube ihn in `sensitiveData.allow`, oder wechsle zu `redact` oder `block`.

### SENSITIVE_CONTENT_REDACTED [#sensitive_content_redacted]

Unter `"redact"` wurden die Treffer in den Werten dieser Keys vor dem Senden durch Tokens ersetzt und in der Übersetzung wieder eingesetzt. Die Meldung nennt die ersten Keys vollständig, ein Treffer in einem Key-Namen steht also darin.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Nichts zu tun.

### SENSITIVE_CONTENT_WITHHELD [#notice-sensitive_content_withheld]

Unter `"block"` oder `"redact"` wurden Keys wegen eines Treffers nicht gesendet und stehen in `sensitiveWithheld`, oder Glossarbegriffe mit einem Treffer blieben aus dem Request. Unter `"redact"` wird ein Key zurückgehalten, wenn der Treffer in seinem Key-Namen liegt oder einen Platzhalter überlappt, oder wenn ein Token nicht genau einmal zurückkam. Die Meldung nennt die ersten Keys vollständig, ein Treffer in einem Key-Namen steht also darin.

- **Ausgelöst von**: `translate` (auch ein Probelauf), `watch`
- **Exit-Code**: `1`, da ein zurückgehaltener Key die Locale `partial` oder `failed` lässt; `0`, wenn nur Glossarbegriffe wegblieben, da die Locale trotzdem gelingt
- **Nächster Schritt**: Entferne den Inhalt oder erlaube ihn in `sensitiveData.allow`; die Keys werden beim nächsten Lauf erneut versucht.

### RUN_CANCELLED [#notice-run_cancelled]

Das `signal` des Laufs wurde abgebrochen, während diese Locale lief. Noch nicht übersetzte Keys wurden nicht gesendet oder ihr Request wurde aufgegeben: sie bleiben für den nächsten Lauf ausstehend, und die Locale ist `partial`, oder `failed`, wenn andere Keys zurückgehalten wurden und keiner ankam. Übersetzungen, die vor dem Abbruch ankamen, wurden geschrieben und erfasst. Die Meldung nennt die Zahl der ausstehenden Keys.

- **Ausgelöst von**: nur das SDK
- **Exit-Code**: keiner: kein CLI-Befehl löst ihn aus
- **Nächster Schritt**: Führe `translate` erneut aus, um die ausstehenden Keys zu senden.

## Provider-Hinweise [#provider-notice-codes]

Ein Provider-Hinweis meldet eine kontrollierte Herabstufung bei einer erfolgreichen Anfrage, als Daten in den `notices` der Locale. Jeder Key eines herabgestuften Batches trägt außerdem den Review-Grund `PROVIDER_DEGRADED`.

### FORMALITY_DOWNGRADED [#formality_downgraded]

Ein angeforderter `formal`- oder `informal`-Ton wurde nicht angewendet, etwa im kostenlosen DeepL-Tarif oder mit Google Cloud Translation Basic.

- **Ausgelöst von**: `translate`, `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe den Ton im Review, oder nutze einen Provider oder Tarif, der Formalität unterstützt.

### GLOSSARY_IGNORED [#glossary_ignored]

Ein Glossar mit vorgeschriebenen Übersetzungen oder beizubehaltenden Begriffen wurde nicht angewendet: DeepL wendet nur eine native Glossar-ID an, und Google Cloud Translation Basic unterstützt kein Glossar.

- **Ausgelöst von**: `translate`, `watch`
- **Exit-Code**: keiner
- **Nächster Schritt**: Prüfe die Glossarbegriffe im Review, oder nutze einen LLM-Provider für glossargebundenen Text.

### PLACEHOLDER_UNSUPPORTED [#placeholder_unsupported]

Mindestens ein Wert blieb bei DeepL, Google Cloud Translation oder LibreTranslate unübersetzt. Ein Wert wird zurückgehalten, wenn ein Platzhalter nicht wörtlich darin steht oder sein Text außerhalb der Platzhalter `<`, `>`, `{` oder `}` enthält: ICU-Argumente wie plural, select oder number, Markup neben einem Platzhalter oder ein Vergleichszeichen (LibreTranslate behält Markup, dort zählen nur geschweifte Klammern). Google hält außerdem einen Wert mit Zeilenumbruch, Tab oder doppeltem Leerzeichen zurück. Ein Ergebnis wird verworfen, wenn eine Markierung verloren, doppelt, verändert oder bloß zurückkommt, oder mit unbekannter Entity oder fremdem Tag. Ein Wert mit Markup und ohne Platzhalter wird unmaskiert gesendet. Ein Token einer anderen Platzhalter-Syntax als der des Formats zählt hier als Platzhalter.

- **Ausgelöst von**: `translate`, `watch`
- **Exit-Code**: `1`: die Keys stehen unter `providerFailures`, und die Locale endet `partial` oder `failed`
- **Nächster Schritt**: Übersetze diese Werte von Hand, oder nutze dafür einen LLM-Provider.
