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 emits are M0089 (redundant ignore), M0145/M0146 (pattern coverage), M0194/M0198 (unused identifier and field 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). moc's other warning codes are 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
M0000–M0001parse and syntax errors; the message, not the code, carries the detail
M0002–M0245type, definedness and lowering errors, mixed with warning codes drawn from the same space
M0250–M0267the 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.3 (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