Error and diagnostic codesalpha
What does this error mean and what do I do about it?
A moxzi diagnostic is an M#### code attached to a source region, a severity and a category, rendered the way moc renders one so editors and habits carry over. The code registry (mops/mo-langutils/src/ErrorCodes.mo, a port of moc's error_codes.ml) lists about 204 error codes and 43 warning codes; 65 are actually emitted — the rest are declared for parity and never raised.
How a diagnostic is printed#
/src/main.mo:4.10-4.19: type error [M0030], type field does not exist in type
note: ...
| Part | Where it comes from |
|---|---|
file:l.c-l.c | the message's region |
type | the category word; warnings drop it |
error / warning / info | Diag.Severity (mops/mo-langutils/src/Diag.mo:36) |
[M0030] | the code; omitted when empty, and always omitted for info |
| notes | rendered one per line, prefixed note: — usually the inferred type |
A build fails when any message has severity #Error (Diag_hasErrors, Diag.mo:253). The CLI's renderer is render_diag in moxzi/src/compile.rs:293; the JSON form emits message, code, level, spans, notes.
The codes you will actually hit#
| Code | Meaning | What to do |
|---|---|---|
| M0220 | this actor or actor class should be declared persistent | add persistent, or build with --default-persistent-actors |
| M0096 | expression of type T cannot produce expected type U | the generic check-mode mismatch; read the note for the inferred type |
| M0057 | unbound variable | typo, missing import, or a name not in scope |
| M0026 | unbound variable in a path | the module qualifier does not resolve |
| M0029 | unbound type | the type name does not resolve |
| M0028 / M0030 | field / type field does not exist | wrong qualifier or wrong package version |
| M0020 | unresolved import | a missing mo: package or a wrong relative path |
| M0006 | import cycle | break the cycle; moxzi names the path |
| M0016 | cannot use x before y has been defined | reorder, or wrap in a function |
| M0031 / M0032 | shared function has a non-shared parameter / return type | only shared types cross a message boundary |
| M0072 | field does not exist in {…} | the record literal is missing it |
| M0073 | expected mutable assignment target | declare the binding var |
| M0077 | a shared function is only allowed as a public field of an actor | move it into the actor |
| M0082 | expected iterable type | .vals() / .keys() |
| M0088 | expected async type | you are awaiting something that is not a future |
| M0037 / M0038 | misplaced await/async; try enclosing in an async function/expression | |
| M0064 | misplaced ! | there is no enclosing do ? { } |
| M0097 | expected function type | you are calling a non-function |
| M0102 / M0103 | cannot infer the type of a wildcard / variable | add an annotation |
| M0112–M0117 | pattern cannot consume the expected type | tuple, option, object, variant, operator and general forms |
| M0119 | show is not defined for this type | debug_show needs a showable type |
| M0124 / M0125 | public actor field has a non-shared function type / is not a manifest function | |
| M0141 | an actor or actor class must be the only non-imported declaration | move declarations into the actor body |
| M0175 | to_candid argument must have a shared type | |
| M0184 / M0261 | cannot infer the type of this or-/and-pattern | annotate it |
| M0189 / M0260 | different bindings in pattern alternatives / bound in both and-pattern legs | |
| M0225 | a mixin cannot be an entry point | include it in an actor |
| M0233 | cannot resolve implicit argument | pass it explicitly |
| M0238 | break/continue outside a loop |
Emission sites are almost entirely in mops/mo-frontend/src/Typing.mo, with Static.mo, Definedness.mo, Resolve.mo and bin/compiler-canister/Main.mo supplying the rest.
Codes with moxzi-specific wording#
| Code | moxzi's wording | Note |
|---|---|---|
| M0069 | non-toplevel actor; an actor can only be declared at the toplevel of a program | moxzi emits M0069 alone where moc also reports M0037 and M0038 — a deliberate divergence, gated by scripts/nontoplevel_actor_matrix.sh |
| M0057 (prim gate) | unbound variable prim / help: did you mean variable Prim? | an authorization gate, not a type error: prim is only available with MOC_UNLOCK_PRIM |
| M0096 (arity form) | call supplies N arguments but the function expects M (with K implicit param(s)); implicit insertion cannot reconcile the difference | a second, more specific M0096 at Main.mo:2710 |
| M0250 | a stable variable under --enhanced-migration carries an initializer | delete it; the migration chain supplies the value |
| M0267 | a stable field the migration chain cannot explain, measured against --stable-baseline — the message names the boundary it was measured at (initial actor or upgrade resuming after migration m2``) | write a migration that produces the field, or correct the baseline |
| M0169 / M0170 / M0216 | the upgrade-compatibility verdicts (dropped variable / incompatible type / silent data loss), from moxzi stable-compatible and the baseline check | same meanings as moc |
| M9000 | unimplemented: <what> | moxzi-only. Not a program error — a compiler feature that is not ported. Report it |
Warnings#
Severity is a property of the message, not of the code. Warnings print on successful builds, before the provenance line. Four are emitted today:
| Code | Meaning |
|---|---|
| M0089 | redundant ignore on an operand already of type () |
| M0254 | a stable field the migration chain does not produce (without --stable-baseline; with one it becomes error M0267) |
| M0265 | mixin capability mismatch |
| M0266 | a float literal with more precision than Float can represent, naming what it rounds to |
The other registered warning codes — including M0194 (unused identifier) and M0145/M0146 (pattern coverage) — are inert, which is a real stderr difference against moc (called out in scripts/shared_type_matrix.sh).
Lint levels exist (mops/mo-sys/src/Flags.mo:47, #Allow/#Warn/#Error). Four codes are suppressed by default: M0223, M0235, M0236, M0237, matching moc's defaults.
M0000 is overloaded#
moxzi uses M0000 for several things moc splits up: parse errors (moc uses M0001), filesystem and import failures, prelude and desugar failures, job authorization refusals, and IR subtype violations (Ill-typed intermediate code: subtype violation). If you are matching on diagnostics programmatically, match the text as well as the code — the corpus harness does exactly that.
Runtime errors#
Traps and rejects, not compile-time diagnostics. Formatted in one place, ic_reject_message at moxzi/runtime/src/machine.rs:328, matching the IC's first line.
| Form | When |
|---|---|
IC0503: Error from Canister <id>: Canister called ic0.trap with message: '<t>'. | an explicit ic0.trap — most Motoko traps |
IC0502: Error from Canister <id>: Canister trapped: <text>. | a recognised wasm trap; currently only stack overflow |
Reject codes follow the IC's numbering (moxzi/runtime/src/sys.rs:28): 1 SYS_FATAL, 2 SYS_TRANSIENT, 3 DESTINATION_INVALID, 4 CANISTER_REJECT, 5 CANISTER_ERROR, 6 SYS_UNKNOWN.
Two messages you will meet that are not codes at all:
| Message | Source |
|---|---|
self-calls nested more than 512 deep (a runaway async chain?) | the shared call-depth cap; the same in the browser and natively |
Canister exceeded the limit of 40000000000 instructions for single message execution | the replica, on-chain only. moxzid kills the message at its own --instruction-limit instead |
Things this page cannot tell you#
Code-to-explanation prose exists for only a handful of codes (M0003, M0037 and a few others carry a long-form .md flag in the registry). There is no per-code explainer command. If a diagnostic is unclear, that is a bug worth filing — see Reporting a bug.
Next#
- Known differences — where moxzi's diagnostic for a program is not moc's.
- Limits — the numbers behind the trap messages above.
- Language support status — what M9000 currently covers.