Metel Error Code Reference
All Metel errors carry a code. Codes are prefixed by phase:
| Prefix | Phase |
|---|---|
P | Parse — invalid source text |
T | Type — type-checker rejection |
R | Runtime — error during execution |
I | Internal — bug in the interpreter (please report) |
Parse errors (P)
P0001 — Syntax error
The source text does not match the Metel grammar.
[P0001] parse error in main.mtl at 12..18 (`let x = ;`): expected expression
Fix: correct the syntax at the indicated position.
P0002 — Invalid integer literal
An integer literal is out of range for i64 (−9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).
[P0002] parse error in main.mtl at 4..24: integer literal '99999999999999999999' is out of range for i64
Fix: use a value that fits in i64, or split the computation.
P0003 — Invalid float literal
A float literal cannot be represented as an f64.
[P0003] parse error in main.mtl at 4..12: invalid float literal '1e9999'
Fix: use a value within the f64 range (~±1.8 × 10³⁰⁸).
Type errors (T)
T0001 — Type mismatch, or an impl that is not allowed
Two types that must be equal are not.
[T0001] type error in main.mtl at 10..20: expected i64, got boolean
Fix: ensure the expression produces the expected type. Add an explicit cast if widening (e.g. x as f64).
The same code also covers an extend block the language does not permit, which is a
distinct situation sharing one code:
- a target that cannot carry the impl at all —
extend { … }: Dropon an anonymous record; - a target with nowhere to register, so its methods could never be found — a tuple, an
anonymous record, a
funtype, or an array whose element is not one of the impl's own type parameters. Onlyextend<T> T[]: Aspect— the array's element spelled exactly as one of the impl's own generics — is implemented today (metel-core#353); - a
dropbody, while destructor invocation is unimplemented (metel-core#292).
[T0001] type error in main.mtl at 3..9: cannot `extend` a tuple type: this block's methods could never be found (metel-core#353). To fix it, use a named struct
Fix: each message names the way forward — usually a named struct, or the generic form where one exists.
T0002 — Annotation required
The type checker cannot infer a type without an explicit annotation.
[T0002] type error in main.mtl at 5..10: cannot infer type of `x`; add a type annotation
Fix: annotate the binding: let x: i64 = ....
T0003 — Undefined name
A name is used but not defined in the current scope.
[T0003] type error in main.mtl at 8..12: undefined name `foo`
Fix: define the variable or function before use, or correct the spelling.
T0004 — Arity mismatch
A function is called with the wrong number of arguments.
[T0004] type error in main.mtl at 5..20: expected 2 arguments, got 3
Fix: pass the exact number of arguments the function declares.
T0005 — Invalid operand types
An operator is applied to operands it does not support. Three forms share this code:
- Mismatched operands. The two sides of a binary operator disagree, e.g.
1 == "x". The message names the operator and both types. - Binary arithmetic/ordering on unsupported types.
- Equality (
==,!=) on anything other than a numeric type,boolean,Stringorchar.==does not yet dispatch through theEqaspect, so structs, enums, arrays, tuples and references are rejected; use.eq(..)on a type that implementsEq.
Since v0.12.0: address-of (
&,&var) applied to a non-addressable expression — a literal, a call result, a struct/enum construction — is no longer one of this code's cases. Both forms now get temporary lifetime extension instead of being rejected; see Expressions — References.
[T0005] type error in main.mtl at 6..13: operator `+` cannot be applied to boolean and i64
Fix: use compatible types, cast one operand, or bind the value to a name so it has an address.
T0006 — Assignment to immutable binding
A write operation targets a let binding. This covers three forms:
- Direct reassignment:
x = newValue - Field assignment through an immutable binding:
point.x = 1 - Taking a mutable reference to an immutable binding:
&var x
[T0006] type error in main.mtl at 3..12: `x` is immutable; use `var x` to allow reassignment
Fix: change the binding declaration to var.
T0007 — Invalid cast
A as cast between incompatible types.
[T0007] type error in main.mtl at 5..15: cannot cast boolean to i64
Fix: only cast between numeric types (i64 as f64). Use an explicit conversion function for other types.
T0008 — Non-exhaustive match
A match expression does not cover all possible values of the scrutinee type.
[T0008] type error in main.mtl at 2..30: match on Colour is non-exhaustive; missing variant `Blue`
Fix: add the missing arms, or add a wildcard arm _ => ....
T0012 — Aspect bound not satisfied
A generic type parameter's bound is not satisfied by the concrete type at the call
site or construction site. Covers both directions: a positive bound (T: Aspect)
requires an implementation that isn't reachable, or a negative bound (T: !Aspect,
RFC-0072) is violated because the concrete type does implement the aspect. Also
covers a conditional extend block's own where-clause bounds (RFC-0036) failing at a
use site — the same check as an ordinary function bound, just reached through an
implementation block's
condition instead of a function's generic parameter.
[T0012] type error in main.mtl at 5..15: `i64` does not implement `Display` (required by `show`)
[T0012] type error in main.mtl at 8..20: `Handle` implements `Drop`; `!Drop` bound not satisfied (required by `move_out`)
[T0012] type error in main.mtl at 3..12: `Pair<i64, SomeNonPrintable>` does not implement `Printable`, because `SomeNonPrintable` does not implement `Printable`
A type satisfying T: Copy automatically satisfies T: !Drop (RFC-0072 §2.3) even
though it implements Drop — this is a narrow, Copy/Drop-specific exception, not a
general rule.
Fix: implement the required aspect for the type, or (for a negative bound) remove the conflicting positive implementation.
T0013 — Ambiguous aspect method/associated-type resolution
Two different aspects define the same method name on the same receiver type, so a
call like value.method() does not have a unique static target — or (RFC-0082 §3a)
two different aspects bound on the same generic type parameter both declare an
associated type of the same name, so a bare projection like T::AssocName doesn't
have a unique target either.
[T0013] type error in main.mtl at 12..20: ambiguous aspect method `label` on type `S`: both `A` and `B` provide this method
[T0013] type error in main.mtl at 8..16: ambiguous associated type `Target`: multiple aspects declare it: Deref, Convert
Fix (method case): rename one of the methods, remove one of the conflicting impls, or change the design so the receiver type does not expose two indistinguishable aspect methods.
Fix (associated-type case): bind the associated type to a fresh type parameter via
an equality-constrained bound instead of projecting it directly — e.g.
fun f<T: Deref<Target = U> + Convert, U>(x: &T) -> U — which resolves unambiguously
since U is an ordinary type parameter, not a projection.
T0014 — Orphan implementation
An extend Type: Aspect block where neither Aspect nor Type's outermost type
constructor is declared in the current module (or std::core, for built-ins).
[T0014] type error in main.mtl at 1..40: orphan implementation: neither `Display` nor `i64` is local to this module
Fix: move the extend block into the module that declares the aspect or the type, or (for
two foreign types) into std::core if this is genuinely a standard-library concern.
T0015 — Conflicting implementation
Two implementations of the same aspect cover the same concrete type — either two
identical extend blocks, or a positive and a negative impl (see Negative Impls in the declarations
reference) for the same concrete type.
[T0015] type error in main.mtl at 1..40: conflicting implementation: `Display` is already implemented for `List<i64>` at 10..30
Fix: remove the duplicate extend block, or narrow one block's type arguments so the two no
longer overlap.
T0016 — Non-diverging -> ! function
A function declared -> ! (RFC-0078) contains a reachable path that doesn't
diverge — most commonly an ordinary return <expr> where <expr> isn't itself
!-typed. A -> ! function promises never to return; the compiler verifies
every control-flow path ends in a diverging expression (a panic, a loop
with no reachable break, or a return/tail expression whose own value is
already !-typed).
[T0016] type error in main.mtl at 1..40: function `bad` is declared `-> !` but does not diverge on all paths
Fix: make every path genuinely diverge (panic(msg), loop { }, or a
recursive/other !-returning call), or drop the -> ! annotation if the
function is meant to return normally.
T0017 — Missing associated type definition
An extend Type: Aspect block omits a type Name = ConcreteType; definition for an
associated type the aspect declares (RFC-0082 §2). Every implementation of an aspect with
associated types must define all of them.
[T0017] type error in main.mtl at 1..40: `IntBox` is missing associated type `Item` required by aspect `Container`
Fix: add the missing type Item = ConcreteType; definition to the extend block.
T0018 — Naming the concrete type of an opaque return value
A function returning impl Aspect (RFC-0037) hides its concrete return type. Using the
result in a position that pins it to a specific type — annotating it, or unifying it with a
concrete type — defeats that, and is rejected.
[T0018] type error in main.mtl at 1..40: cannot name the concrete type of an opaque `impl Aspect` return value; use `impl Aspect` or a generic bound instead (resolved to `i64`)
Fix: keep the value opaque — annotate it as impl Aspect too, or accept it through a
generic parameter with the same bound.
T0019 — Use of moved value
Since v0.12.0, under
--move-checkonly. Move checking is off by default in this release.
An ownership rule from RFC-0071 §1/§7 was violated. Seven distinct situations share this code, each with its own message:
- a value used after it was moved;
- a partially moved value used as a whole;
- a partial move out of a type that implements
Drop, which is never allowed; - a move out of an array element, which is banned outright;
- a move of a non-
Copyelement out of a borrowedT[]view; - a
&varbinding moved by a use that is not a reborrow; - a by-value
selfmethod called through a reference — a reference only grants access, never ownership, so its pointee cannot be moved out, unless the pointee's own type isCopy(in which case the method reads a copy, exactly asT: Copyalready permits at read-copy positions per §3a) (metel-core#348).
Each message names the binding and the location of the move. When the move happened on an earlier iteration of an enclosing loop, the message says so — a loop-carried move is usually the same expression as the use, one iteration later, so naming only its location would point back at the line you are already reading.
[T0019] type error in main.mtl at 30..40: use of moved value `p`: `p` was moved at main.mtl:30:14
[T0019] type error in main.mtl at 12..20: cannot partially move value `h`: `h.name` belongs to a `Drop` type
[T0019] type error in main.mtl at 8..14: cannot move from `xs[0]`: array element moves are not allowed
[T0019] type error in main.mtl at 62..70: use of moved value `s`: `s` was moved here on an earlier iteration
[T0019] type error in main.mtl at 40..48: cannot move `(*r)` out of a reference: a by-value `self` method cannot be called through a reference
Fix: depending on the rule — borrow instead of moving (&x), clone the value, move the
whole value rather than a field of a Drop type, or index-and-copy rather than moving an
element out of an array.
Runtime errors (R)
R0001 — No main function defined
Execution requires a main function but none was found.
[R0001] runtime error in main.mtl at 0..0: no main() function defined
Fix: add fun main() { ... } to your program.
R0002 — main is not a valid entry point
main exists but is generic or is not a function.
[R0002] runtime error in main.mtl at 0..0: main() is generic — not supported in v0.1
Fix: main must be a concrete, non-generic function with no parameters.
R0003 — Undefined variable at runtime
A variable name is not found in the current environment. This can occur when a variable is used before it is defined in a branch that the type-checker did not flag.
[R0003] runtime error in main.mtl at 10..15: undefined variable `x`
R0004 — Index out of bounds
An array index is negative or ≥ the array length.
[R0004] runtime error in main.mtl at 5..10: index 5 out of bounds (len 3)
Fix: check that the index is within 0..array.len() before access.
R0005 — Tuple index out of bounds
A tuple element is accessed by an index that does not exist.
[R0005] runtime error in main.mtl at 5..10: tuple index 3 out of bounds
Fix: tuple indices are fixed at compile time; verify the index against the tuple's declared length.
R0006 — Non-exhaustive match at runtime
A match expression reached its end without any arm matching. This indicates a pattern that the type checker approved as exhaustive but that is not, which is a known limitation.
[R0006] runtime error in main.mtl at 2..30: match: no arm matched scrutinee
R0007 — Arithmetic error
Integer division or remainder by zero.
[R0007] runtime error in main.mtl at 8..13: division by zero
Fix: guard with a zero check before dividing.
R0008 — Field not found
A struct or enum value does not have the accessed field.
[R0008] runtime error in main.mtl at 5..12: no field `colour` on value
Fix: check the field name against the type definition.
R0009 — Method not found
A method call cannot be resolved for the receiver type.
[R0009] runtime error in main.mtl at 5..20: no method `draw` on `Circle`
Fix: define the method in an extend block for the type.
R0010 — Call on non-callable value
A call expression (f(...)) is applied to a value that is not a function or closure.
[R0010] runtime error in main.mtl at 3..8: call: expected a closure or builtin
R0011 — Invalid for-in iterator
A for x in expr loop where expr does not evaluate to an Array or Range.
[R0011] runtime error in main.mtl at 1..20: for-in: expected Array or Range
Fix: ensure the iterable is an array literal, a range (a..b), or a variable of those types.
R0012 — Error propagation on non-Result value
The ? operator is applied to a value that is not a Result.
[R0012] runtime error in main.mtl at 5..10: ?: expected a Result value
Fix: only use ? on expressions whose type is Result[T, E].
Note: this misuse is actually caught statically.
?constrains its operand's type toResult<T, E>during type inference (infer_propagate_error), so a non-Resultoperand is rejected as aT0001type mismatch before the program ever runs.R0012does not appear in the interpreter'sRuntimeErrorCodeenum today and is unreachable in practice — kept here for the code number, not because the described runtime error can currently occur. (Found while investigating issue #232; not fixed as part of it, since removing a documented code is a separate decision from the yolo/conversion-method work that issue tracked.)
R0013 — Assertion failed
assert(cond) or assert(cond, msg) is called with cond evaluating to
false. The panic message is the fixed string "assertion failed" for the
one-argument form, or the caller-supplied msg for the two-argument form.
[R0013] runtime error in main.mtl at 5..10: assertion failed
Fix: this is not a bug in the interpreter — it means the asserted condition was actually false at runtime. Fix the condition, or the code that led to it.
R0014 — Unwrap on None/Err
.yolo() is called on a Perhaps<T> that is None, or a Result<T, E> that is
Err. For Result, the panic message includes the Err value's debug
representation.
[R0014] runtime error in main.mtl at 5..10: called `.yolo()` on a `None` value
[R0014] runtime error in main.mtl at 5..10: called `.yolo()` on an `Err` value: "not found"
Fix: this is not a bug in the interpreter — .yolo() is meant only for cases
where None/Err represents a logic error that should never occur in correct
code. Use match, .unwrap_or, .unwrap_or_else, or (for Result) ? to
handle the expected case instead.
R0015 — Explicit panic
panic(msg) (RFC-0078) is called. Always panics unconditionally with msg.
[R0015] runtime error in main.mtl at 5..10: boom
Fix: this is not a bug in the interpreter — panic is meant for logic
errors that should never occur in correct code. Handle the expected case with
ordinary control flow instead of reaching the panic call.
Internal errors (I)
I0001 — Internal interpreter error
The interpreter reached an impossible state. This is a bug in the interpreter — the typechecker should have caught it before execution.
[I0001] internal error: binop: unsupported operand types (typechecker should have caught this)
What to do: please file a bug report at the Metel issue tracker with the source program that triggered this error.
I0002 — Not implemented
The program uses a language feature that is not yet supported in this version of the interpreter.
[I0002] internal error: generic functions are not supported in v0.1
What to do: check the changelog for the current supported feature set and the release plan for the planned implementation milestone.