Skip to content

Fix configuration errors

If you received this configuration for an assignment, send the error text and filename to its administrator. If you maintain it, find the message below, correct the setting, and reload the file in MLabel.

In a repository checkout with dependencies installed, you can also validate without opening the app:

Terminal window
pnpm validate path/to/config.jsonc

The examples below use representative field names. Your message will name the field or card in your file.

Each stage only runs if the one before it passed, so fixing an error can reveal new ones. Later checks run only after earlier checks pass.

Stage Checks
1. Syntax Is it parseable JSONC?
2. Shape Are the keys and types right? Unknown keys, wrong types, bad names.
3. Coherence Do the parts agree? Dangling references, type mismatches, shortcut collisions.

Within a stage, everything is reported at once — there is no fix-one-rerun-find-the-next loop inside a stage. But a single unknown key in stage 2 hides every stage 3 diagnostic behind it:

"network": { "updateCheck": false } ← one typo
→ 1 problem: Unrecognized key: "updateCheck"
fix it, re-run
→ 2 problems: Type "integer" does not match input field "prompt" of type "text".
Shortcut "mod+v" is reserved by the app or the OS.

Repeat until validation succeeds, then test the form with sample data.

This config has no \version`. MLabel 0.3 and later require “version”: 2 and a rewritten schema.`

Section titled “This config has no \version`. MLabel 0.3 and later require “version”: 2 and a rewritten schema.`”

Add "version": 2 at the top level. If the file predates v2, it needs more than the key — see Versioning.

Unsupported config version 1. This build reads version 2.

Section titled “Unsupported config version 1. This build reads version 2.”

The config is written for a different format version. Both directions are refused: a newer config in an older build fails just as cleanly.

JSONC syntax error: PropertyNameExpected (and similar)

Section titled “JSONC syntax error: PropertyNameExpected (and similar)”

Malformed JSON. Comments and trailing commas are allowed — this is .jsonc — so the cause is usually a missing comma, an unclosed brace, or a stray one.

You may see two syntax errors for one mistake; fix the first and re-run.

A typo, or a key that does not exist on that object. Every object in the config is strict.

Check spelling and which object the setting belongs to. The update key is updateChecks, with a final s.

The one place unknown keys are allowed is adapterConfig, which is owned by the adapter.

must be a column name: letters, digits, _ or -, with optional inner spaces

Section titled “must be a column name: letters, digits, _ or -, with optional inner spaces”

A field or card name used a forbidden character. . [ ] * are reserved for a future rule path grammar, and leading or trailing whitespace is excluded because it would not round-trip through a CSV header. See Fields.

Also Duplicate output field, Duplicate input card, Duplicate output card. Names must be unique within their side. An input id and an output id are fine and unrelated.

Card "c" references unknown input field "missing".

Section titled “Card "c" references unknown input field "missing".”

A card’s use lists a field that side does not declare. Check for a typo, or a field declared on the other side.

Table column "C" references unknown object field "zzz".

Section titled “Table column "C" references unknown object field "zzz".”

A table column names a member the object does not have. Table columns address their own object’s fields, not the top-level ones — which is easy to forget, because the object carrying the column list is usually nested inside an array or a map.

Rule references unknown input field "ghost".

Section titled “Rule references unknown input field "ghost".”

A rule’s when.field, when.otherField, or an entry in appliesTo names a field that does not exist. Rules can only see input fields.

ui.appTitle.field names a field that does not exist.

A fill: { "kind": "copy" } field points at an input column that is not declared. Remember from defaults to the field’s own name, so this also fires when you add a copy field whose name has no input counterpart.

Type "integer" does not match input field "id" of type "text".

Section titled “Type "integer" does not match input field "id" of type "text".”

A copied field’s declared type must be identical to its source. Prepare re-reads *-output cell by cell using the declared type, so a mismatch silently mistypes the column on the way back in. Fix whichever side is wrong.

"object" fields cannot be filled by a user; give the field a \fill`.`

Section titled “"object" fields cannot be filled by a user; give the field a \fill`.`”

Also for map. There is no widget that could capture an arbitrary nested structure, so an output field of either type should copy a compatible input value with fill.kind: "copy". See Widgets.

A widget on a field nobody fills. Remove it. Same for timestamp.

A "timestamp" field renders no widget, so there is nothing to focus.

Section titled “A "timestamp" field renders no widget, so there is nothing to focus.”

A shortcut on a field nobody fills. Remove it. Same for copy.

Shortcut "z" is already used by choice "y" on "f".

Section titled “Shortcut "z" is already used by choice "y" on "f".”

Field chords and choice chords share one namespace across the whole config, because choice chords fire app-wide rather than only while their field has focus. Two claimants would be a genuine ambiguity. Pick a different chord.

Shortcut "mod+v" is reserved by the app or the OS.

Section titled “Shortcut "mod+v" is reserved by the app or the OS.”

The chord belongs to Paste, Quit, mode switching, or another built-in. The full list is in Shortcuts. A bare letter that merely appears inside a reserved chord is fine — "c" is unrelated to mod+c.

The chord did not parse. It must be zero or more of mod ctrl alt shift meta, each followed by +, then a letter, digit, or supported named key such as enter or up. "ctrl+" has no key; "ctrl+ab" has two.

Give exactly one of \value` or `otherField`.`

Section titled “Give exactly one of \value` or `otherField`.`”

The six comparison operators compare against a literal or another field, never both and never neither.

A pattern — on a text field or in a matches condition — is not a valid JavaScript regex. Patterns are compiled when the config loads precisely so this surfaces here rather than mid-labeling. The usual cause is an unescaped bracket: "([" should be "\\(\\[".

Remember JSON escaping: a regex \d is written "\\d" in a config file.

Too small: expected array to have >=1 items

Section titled “Too small: expected array to have >=1 items”

An empty list where at least one entry is required — choices on an enum, fields on either side, rows on a card, use on a row, columns on a table.

Invalid input: expected "text" (or similar, on type)

Section titled “Invalid input: expected "text" (or similar, on type)”

The type is not one of the nine. See Value types. With $schema set, your editor offers the valid values in a dropdown.

minLength on a number, min on text, choices on a boolean — constraints live on the type that owns them. This surfaces as an unrecognised key for the type you wrote.

/tmp/errs.jsonc:22:30 (output.fields.1.type) — Type "integer" does not match …
└── file └ line
└ column
└── dotted path to the offending key

The path is the fastest way in: output.fields.1.type is the type of the second field in output.fields. When a cross-field check names a path with no exact source node, the location degrades to the nearest ancestor — start with the indicated parent object when there is no exact source location.

Set "$schema": "https://mlabel.vlad.gg/mlabel.schema.json" and open the config in an editor. Most of these become a squiggle under the exact character, before you ever run the validator.