moxzi
Docs / CLI / Reading diagnostics

Reading diagnosticsalpha

What do moxzi's error codes mean and what should I put in a bug report?

moxzi renders diagnostics the way moc does — file:line.col-line.col: kind [Mxxxx], message — using moc's own code numbering, so editor tooling, search results and habits carry over unchanged. A failing build prints its errors; a successful build prints its warnings and then the provenance line. Warning coverage is narrower than moc's — the codes the compiler currently emits are M0089 (unused pattern binding), M0254 (a stable field the migration chain does not produce), M0265 (mixin capability) and M0266 (a float literal with more precision than Float holds — a check that found real miscompiles when it was built, so take it seriously). Codes moc emits that moxzi does not yet, notably M0194 unused-identifier and the M0145/M0146 pattern-coverage family, are simply absent: a warning-clean moxzi build is not evidence of a warning-clean moc build.

Anatomy of a diagnostic#

/src/e.mo:1.33-1.37: type error [M0050], literal of type Text does not have expected type Nat
PartMeaning
/src/e.mothe VFS path, not your disk path — /src/… for project sources, /pkg/<name>/… for packages
1.33-1.37line.column of the start and end of the offending region
type errorcategory plus severity; parse error is the other common form
[M0050]the code, shared with moc
the restthe message

Because the location is a VFS path, moxzi deps is the tool that maps it back to a file on disk.

Codes you will actually meet#

Every one of these was produced by moxzi build on a three-line program:

CodeYou wrotemoxzi says
M0000persistent actor { public func f() : async Nat { 1 };parse error [M0000], expected } (object body), got EOF
M0020import X "missing";type error [M0020], unresolved import missing
M0031a shared function taking a function argumenttype error [M0031], shared function has non-shared parameter type …
M0050var x : Nat = "hi"type error [M0050], literal of type Text does not have expected type Nat
M0057a reference to an undeclared nametype error [M0057], unbound variable y
M0069an actor { … } nested inside a functiontype error [M0069], non-toplevel actor; an actor can only be declared at the toplevel of a program
M0072{ a = 1 }.btype error [M0072], field b does not exist in object with fields: a
M0096a value that is not a literal failing a check-mode subtype testtype error [M0096], expression of type … cannot produce expected type …
M0220actor { … } with no persistenttype error [M0220], this actor or actor class should be declared 'persistent'

M0050 and M0096 are the pair worth understanding: moc reserves M0050 for the literal case and uses M0096 for every other check-mode subtype failure, and moxzi follows that split deliberately.

The code space#

mops/mo-langutils/src/ErrorCodes.mo is the canonical list — a port of moc's error_codes.ml. It carries 206 error codes and 42 warning codes, each flagged with whether moc ships a long-form explanation for it.

RangeWhat lives there
M0000M0001parse and syntax errors; the message, not the code, carries the detail
M0002M0245type, definedness and lowering errors, mixed with warning codes drawn from the same space
M0250M0267the enhanced-migration family: M0250 (initializer on a chain-managed stable variable), M0254/M0267 (a field the chain does not produce — warning without a --stable-baseline, error with one), M0169/M0170/M0216 at each chain link and at the baseline boundary
M9000moxzi-specific: unimplemented: … — a construct this compiler does not handle yet

M9000 is the one code that is not moc's and is always worth reporting. It means the compiler reached a form it has no case for (infer_exp: unimplemented expression form, and similar) rather than that your program is wrong.

Four warning codes ship disabled by default — M0223, M0235, M0236 and M0237, the "redundant type instantiation" and contextual-dot suggestions — matching moc's own defaults.

The parser's depth cap#

The parser refuses to descend past 128 levels and says so before it unwinds:

/src/deep2.mo:1.183-1.184: parse error [M0000], expression nested too deeply (limit 128)
/src/deep2.mo:1.183-1.184: parse error [M0000], expected ) (parens), got (
…

The first line is the real diagnostic; the rest are the parser resynchronising. Hand-written code does not approach this. Machine-generated code should chunk its expressions.

Failures that are not diagnostics#

Two shapes of output mean something other than "your program is wrong":

OutputMeaning
warning: could not resolve import "…"; not uploading itmoxzi could not find the import on disk. Not fatal — the compiler may still resolve it — but it is the usual cause of a much more confusing type error a moment later
Error: canister trapped: …the compiler itself failed. There is no source location, because there was no diagnostic. This is always a bug

Here is a real one, on a program moc rejects cleanly:

printf 'persistent actor { public func f() : Nat { 1 } };\n' > oneway.mo
moxzi build oneway.mo -o oneway.wasm
Error: canister trapped: await: oneway body not a block
moc --check oneway.mo
oneway.mo:1.38-1.41: type error [M0035], shared function must have syntactic return type '()' or 'async <typ>'

moc reports M0035 with a location; moxzi crashes in lowering. That gap — a missing front-end check letting a bad program through to a later stage — is exactly what a bug report should capture.

What a good bug report contains#

ItemHow to get it
A minimal .mocut until removing one more line makes the failure disappear; three lines is a good target
The exact moxzi outputcopy it verbatim, including the provenance line
moxzi info outputnames the compiler and linker wasm and their SHA-256 hashes — the build being reported
moc's output on the same filemoc --check file.mo, plus moc --version
Which is rightsay whether you expect it to compile, and why

The template:

moxzi --version                      # moxzi 0.1.0-alpha.1 (7eb76f61c9)
moxzi info                           # compiler + linker paths and sha256
moxzi build bug.mo -o bug.wasm       # the failing command, verbatim output
moc --version && moc --check bug.mo  # the reference compiler's verdict

moc is the oracle for this project. A report that pairs both outputs on one small file is actionable; one that describes the failure in prose usually is not. If the two disagree on which code to emit for the same rejection, that is still a bug — the codes are meant to match.

Things you cannot do#

Why
Get long-form explanationsmoc's --explain and its per-code markdown files are not shipped; ErrorCodes.mo tracks which codes have one upstream
Get JSON or AI-formatted errors--error-format and --ai-errors have no equivalent
Change a code's severity-A, -W, -E and -Werror have no equivalent
Continue after the first batchthe compile stops at the failing step and reports what that step produced

Next#

On this pageAnatomy of a diagnosticCodes you will actually meetThe code spaceThe parser&#x27;s depth capFailures that are not diagnosticsWhat a good bug report containsThings you cannot doNext