Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Diagnostics

Every message runtime model validate can produce, by code.

Codes are permanent. Retiring a check retires its number with it, and a number is never reused — so a code in a script, a ticket or a runbook means the same thing forever.

A diagnostic names the file, the path within it, what is wrong, and — wherever there is an answer — what to write instead. If one of these is ever unclear, that is worth reporting: the premise of the product is that models are written by people and language models working from the schema and these messages.

$ runtime model validate myapp
error[M203]: `precision` is not a parameter of type `string`
  --> modules/sales/domain.yaml (entities[0].attributes[1])
  help: remove it, or change the type to `decimal`

Parse

The file could not be read as a model at all: it is missing, it is not YAML, or it does not match the schema.

CodeMeaning
M001A file the bundle requires is not there.
M002The file is not well-formed YAML.
M003The YAML is well-formed but does not match the schema.
M004schemaVersion is a version this runtime does not know.

Resolve

The file parsed, and something it names does not exist.

CodeMeaning
M101app.yaml lists a module with no directory.
M102A file’s module: disagrees with the directory it is in.
M103An association targets an entity that does not exist.
M104An index or access rule names an attribute that does not exist.
M105A user role grants a module role that does not exist.
M106roleMapping or anonymousRole names a user role that does not exist.
M107A flow names a script file the bundle does not contain.
M108A flow’s allow names a role this module does not define.
M109A metric’s label names an attribute the entity does not have.

Check

Everything named exists, and something about it does not make sense.

CodeMeaning
M201A name does not follow the casing convention for its kind.
M202Two things in the same scope share a name.
M203A type-specific parameter was given for a type that has no such parameter, such as precision on a string.
M204A type-specific parameter that is required for this type is missing, such as a decimal without precision.
M205A parameter is present but its value cannot be satisfied.
M206A default cannot be represented in the attribute’s type.
M207An index lists no attributes.
M208previousName is the same as name, which declares nothing.
M209Two elements claim the same previousName.
M210A metric label names an attribute whose type is unbounded.
M211A metric name does not follow the OpenTelemetry naming convention.
M212A metric’s when uses something a committed row cannot answer.

Constraints

A constraint or condition expression is wrong.

CodeMeaning
M301A constraint expression does not parse.
M302A path in a constraint does not resolve against the domain model.
M303A comparison puts two incompatible types either side of an operator.

Warnings

Legal, and nearly always unfinished. These do not stop a model from loading.

CodeMeaning
M901An entity with no attributes.
M902A role grants access to an entity in a different module.
M903A flow no role may invoke.
M904A metric no operation triggers.

Severity

M0xx through M3xx are errors: the model does not load.

M9xx are warnings: the model loads and runs. They exist because the thing they describe is legal and almost always a mistake in progress — a flow no role can invoke will never be called, and a metric nothing triggers will read zero forever, which looks exactly like the thing never happening.

The three passes

Which pass reports a problem determines how good the message can be, which is why they are separate:

  1. Parse — is this YAML, and does it match the schema? Nothing is known about the model yet, so the message is about syntax and shape.
  2. Resolve — does sales.Customer exist, does that attribute exist on it? Names can now be checked, and a near-miss gets a suggestion.
  3. Check — is this expression well-typed, is this parameter applicable, does this default fit? The whole model is known, so the message can be specific.

A failure in an early pass stops the later ones for that file, because a message derived from a half-understood model is worse than no message.

Keeping this page honest

The table above is generated from the runtime’s Code enum. Codes are added rarely and never removed, so it drifts slowly — but it does drift. To check:

grep -oE '"M[0-9]{3}"' ../runtime/crates/runtime-model/src/diagnostic.rs \
  | tr -d '"' | sort -u > /tmp/actual
grep -oE 'M[0-9]{3}' src/reference/diagnostics.md | sort -u > /tmp/documented
diff /tmp/actual /tmp/documented

A code in the runtime and not here is a message somebody will meet with nothing to look up.