Error Handling
MIND provides comprehensive error diagnostics with detailed messages, source locations, and actionable suggestions.
Error Codes
Every diagnostic carries a stable code naming the Core v1 pipeline phase that produced it. The leading digit isthe phase — there is one code space, and it is partitioned by compiler stage, not by error kind:
| Phase | Code | Description |
|---|---|---|
| Parse | E1xxx | Syntax errors |
| Type-check | E2xxx | Type mismatches, inference failures, shape validation |
| IR verification | E3xxx | Failures of the public IR invariants |
| Autodiff | E4xxx | Non-differentiable or ambiguous gradient requests |
| MLIR lowering | E5xxx | Failures translating canonical IR into MLIR |
Shape validation for Core v1 operators is surfaced during type checking, inside the E2xxx space:
E2101— broadcast compatibilityE2102— rank or shape expectation mismatches (including invalid reductions)E2103— matmul inner-dimension mismatches
The MAP protocol server returns short transport-layer codes (E005, E101–E104) in its own response space. Those are protocol responses, not compiler diagnostics, and never overlap the four-digit pipeline codes above. See the MAP protocol page.
Diagnostic formats
mindc emits human, single-line, and machine-readable diagnostics:
mindc --diagnostic-format human # default; multi-line with spans and notes mindc --diagnostic-format short # single line, grep-friendly mindc --diagnostic-format json # one diagnostic per line of JSON
Human output uses consistent phase prefixes (error[parse], error[type-check], …), adds caret highlights when a span is available, and respects --color / MINDC_COLOR. Every error variant propagates a non-zero exit code.
Example Diagnostics
Parse error:
error[parse][E1001]: unexpected `)`, expected an expression --> parseerr.mind:2:13 | let x = ); | ^
Type error — MIND has no implicit int↔float conversion (RFC 0011):
error[type-check][E2015]: no implicit int↔float conversion (RFC 0011); write the value in the annotated type (e.g. `5.0`) or use an explicit `as` cast --> typemismatch.mind:2:21 | let loss: i64 = 1.5; | ^^^
Implicit narrowing is rejected rather than silently truncating:
error[type-check][E2004]: implicit narrowing Scalar[i64] -> Scalar[i32] loses data for `small`; use an explicit `as Scalar[i32]` cast --> narrow.mind:3:22 | let small: i32 = big; | ^^^
Unknown identifiers carry a suggestion:
error[type-check][E2002]: unknown identifier `nope` — did you mean `None`? --> undef.mind:2:12 | return nope; | ^^^^
Machine-readable diagnostics
--diagnostic-format json emits one line-delimited JSON object per diagnostic, with a stable shape:
{"phase":"type-check","code":"E2015","severity":"error","message":"no implicit int↔float conversion (RFC 0011); write the value in the annotated type (e.g. `5.0`) or use an explicit `as` cast","span":{"file":"typemismatch.mind","line":2,"column":21,"length":3},"notes":[],"help":null}Runtime faults
The E1xxx–E5xxx codes above are compile-timediagnostics. At runtime, MIND’s rule is that a fault is deterministicrather than undefined: an out-of-bounds array access is a deterministic bounds trap, never a clamp and never a silent read of adjacent memory. A compile-provable out-of-bounds access may be rejected at compile time instead.
The observable form of that trap is currently an ABI detail, not settled language semantics: the native backend exits with a fixed status, and the reference evaluator raises a hard error naming the index and the length. A typed panic / Resultsurface for runtime faults is not yet shipped, so no runtime error-code space is defined. Arithmetic that other languages leave undefined is definedinstead of trapped — see the determinism contract for x / 0, INT_MIN / -1, overflow, and oversized shifts.
Result Type
For recoverable errors, use the Result type:
fn load_model(path: &[u8]) -> Result<Model, Error> {
if !exists(path) {
return Err(Error::NotFound(path));
}
// ...
Ok(model)
}
fn main() {
match load_model("model.mind.bin") {
Ok(model) => run(model),
Err(e) => print("Failed to load: ", e),
}
}Sum types and pattern matching (Result/Ok/Err with match) are part of the executable subset today, and the type checker fails loudly on nonexistent enum variants, undeclared assignment targets, return-type and condition scalar-class mismatches, and calls to non-function values. Slice-typed parameters such as &[u8]are shown for illustration — slices are not yet in the executable subset.
Learn More
See the full error catalog at mind-spec/errors.md.