StringLane

Browse docsValidation Code Reference
Reference

Validation Code Reference

Every issue code StringLane reports, its severity, and what it means. The same codes appear in the desktop app Issues Panel, in stringlane check, and in the MCP validation tools.

Last updated

Every finding carries a stable code. Branch on that rather than on the message, which is written for a person and may be reworded.

Severity is what StringLane thinks of the finding. What fails your build is a separate decision: by default any finding not in your baseline sets exit 1, and --fail-on narrows that to the codes you name.

Errors#

Something is structurally wrong. These are the findings that break an app rather than read badly.

CodeMeaning
missing_keyA key present in the base locale has no value in this locale. Also raised per plural quantity: a language needing many and not having it is missing, even though the key exists
placeholder_mismatchThe translation's placeholders do not match the source's. A missing or invented {name} is a crash or a literal brace in the UI
format_placeholder_mismatchThe same, for printf-style format specifiers such as %@, %d, %1$s. Type and count both have to line up
malformed_placeholderA placeholder that is not valid syntax for the format at all
markup_mismatchHTML or XML tags inside the value do not match the source's: a dropped closing tag, or one the source did not have
icu_parse_errorThe value is not valid ICU MessageFormat at all, so nothing downstream can read it
icu_missing_plural_categoryAn ICU plural is missing a category this locale's CLDR rules require
select_branch_missingAn ICU select or selectordinal is missing a branch the base declared, or an ordinal branch CLDR requires for this locale. The missing case renders nothing

Warnings#

Legal, and probably not what you meant.

CodeMeaning
untranslatedThe value is identical to the base locale. Correct for a product name, suspicious for a sentence
punctuation_mismatchTrailing punctuation differs from the source, or the locale's own convention is broken — French needs a non-breaking space before ! and :
whitespace_mismatchLeading or trailing whitespace differs from the source. Invisible in an editor, visible when the string is concatenated
double_spaceTwo consecutive spaces inside the value
zero_width_spaceA zero-width character is present. Usually arrived by copy-paste and matches nothing a user can type
max_length_exceededThe value is longer than the keyConstraints limit set for this key
source_length_exceededThe base value already exceeds its own limit, so every translation will too
source_positional_placeholdersThe base string uses unnamed positional placeholders such as %@ and %d, which a language with different word order cannot reorder. Use indexed forms such as %1$s
guarded_word_violationA term listed in guardedWords was translated instead of being kept verbatim
icu_pound_literalA literal # appears inside an ICU plural where it will be substituted for the number
same_plural_formsTwo plural categories in this locale have identical text, which usually means the distinction was not translated
ambiguous_origin_prefixTwo origins in a multi-origin project would claim the same merged-key prefix. One is prefixed differently so neither can take the other's keys, and this says which
duplicate_module_keyThe same key exists in two origins. One of them wins, and this names the winner

Info#

Worth a look, never worth failing a build over.

CodeMeaning
inconsistent_translationThe same source string is translated differently in different keys
reused_translationOne translated string is used for several different source strings
duplicated_wordA word repeats consecutively in the value
expansion_budget_exceededThe translation is much longer than a translation of a source that length usually needs, so it may break the layout. A budget, not a limit: max_length_exceeded is the limit you set yourself
select_branch_extraAn ICU select carries a branch the base did not declare. It renders correctly when selected, so this is reported to be seen rather than because it is wrong
unused_keyNo call site in your source code names this key
undefined_keyYour source code calls this key and no locale file defines it

The last two come from the source-code scan rather than from reading your locale files, so they only exist on a run that read your code. They are info deliberately: upgrading the CLI must not turn a pipeline red, and a recorded baseline must not flip. --fail-on unused_key opts in, and --no-scan turns the scan off — but not both, which is refused rather than silently never firing. Neither is a verdict: see Unused keys for the four ways a live key lands in that list.

Choosing what fails CI#

Start narrow and widen. The errors are the ones that break a running app:

stringlane check . --fail-on missing_key,placeholder_mismatch,format_placeholder_mismatch,malformed_placeholder,markup_mismatch

If the project already carries a great deal of this, do not encode it in --fail-on. Record a baseline instead, so the debt stays visible and only new findings can fail: see Inspect and check.

Where these appear#

The same codes surface in three places, because they come from one validator:

  • the desktop app's Issues Panel, as validation badges;
  • stringlane check, in the terminal and in the --json envelope;
  • the MCP validate_translations and apply_translations tools, which is what stops an agent writing a broken translation.

Not every code can fire on every format. A format with no native comment syntax cannot raise findings about comments, and format_placeholder_mismatch is about printf-style specifiers, so it is an Apple and Android concern rather than an ARB one.

Frequently asked questions

Which StringLane issues fail a CI build?
By default every finding that is not in your committed baseline sets exit 1, whatever its severity. Pass --fail-on with a comma-separated list of codes to narrow that to the ones you care about; it can only soften the result, never harden it.
Are the same validation rules used in the app and the CLI?
Yes. The desktop app, stringlane check and the MCP validate_translations tool are built on one validator over the same files, rather than three implementations of the same rules that drift apart.