Skip to content

Diagnostics ​

Status: M1 increment 1a. Lists every diagnostic code the compiler can emit. Codes are stable: a retired code is never reused. Source of truth in code: DiagnosticCodes (src/Nova.Compiler/Diagnostics/Diagnostic.cs).

Format ​

text
<path>:<line>:<column>: error[N0100]: expected ';', found 'let'
  |
2 |     let x = 1
  |              ^
  • <path> is the path as given on the command line (never made absolute), so output is reproducible.
  • Line and column are 1-based. Columns count UTF-16 code units (grammar.md §1.1).
  • Diagnostics are emitted in the order they are found. The lexer finishes before the parser starts, so all lexical errors of a file come before its syntax errors.
  • --diagnostics-format=json gives the same diagnostics as one JSON document, with fixes, and novac explain <code> prints a code's row (M12; tooling.md §5).

Recovery policy ​

The parser reports one diagnostic per broken statement or item, then re-synchronises (grammar.md §3). The parse-fail corpus enforces this: each test lists exactly the expected diagnostics, so any cascade fails the test.

Codes ​

Lexer (N0001–N0099) ​

CodeMeaningExample
N0001Unexpected character (including non-ASCII outside literals and comments)let a = 1 # 2;
N0002(unassigned)
N0003Unterminated block comment/* ... at EOF
N0004Integer literal does not fit in 64 bits18446744073709551616
N0005Unterminated string literal (newline or EOF before ")"abc
N0006Invalid escape sequence, or \u{...} that is not a Unicode scalar value"\q", "\u{D800}"
N0007Invalid char literal: empty, more than one character, or unterminated'', 'ab'
N0008Invalid digit for the radix, or no digits after a radix prefix0b102, 0x
N0009Unknown literal suffix12abc, 1f32 (float suffix needs a float literal)
N0010Misplaced digit separator _ (must sit between two digits)1__0, 0x_FF, 1_.5

Parser (N0100–N0199) ​

CodeMeaningExample
N0100Expected a specific tokenmissing ;, ( after if, } before fn
N0101Expected an item (fn or const) at the top levellet x = 1;, struct S {} (not in M1)
N0102Expected an expressionlet a = ;
N0103Comparison operators chaineda < b < c
N0104Invalid assignment target1 = 2;, f() = 3;
N0105Expected a typefn f(x: ) {}
N0106Namespace declaration not first in the filefn a() {} then namespace X;
N0107Expected a field or fn inside a struct bodystruct A { 42; }
N0108Expected a match pattern (_, a literal, or E.V(…))match (n) { + => { } }
N0109An import declaration after an itemfn a() {} then import geometry;

Names, types and flow (N0200–N0299) ​

Semantic checks run only when every file parsed without errors.

CodeMeaningExample
N0200Name not found (variable, function, or built-in member)missing, Console.print(1)
N0201Item defined twice in the packagetwo fn twice()
N0202Parameter declared twicefn f(a: i32, a: i32)
N0203Local redeclares a local or parameter in scope (no shadowing of locals)let x = 1; let x = 2;
N0204Unknown type namefn f(a: int)
N0205Type mismatch against the expected typelet a: bool = 1;, if (n) {}
N0206Integer literal out of range for its type256u8, let c: i8 = 128;
N0207Operator not applicable to the operand types (includes mixed types, signed bitwise ops, negating unsigned values)a + b with u8/i32, s & s with i32
N0208as conversion that can lose informationa as u32 with a: i32
N0209Wrong number of argumentstwo(1)
N0210Not callable, or a function or built-in used as a valuelocal(), let f = two;
N0211Assignment to an immutable binding (let, parameter, constant, function)param = 3;
N0212Local read before it is definitely assignedvar x: i32; return x;
N0213End of a non-void function is reachablefn f() -> i32 { }
N0214break/continue outside a loopbreak; at function level
N0215return with or without a value contradicts the return typereturn 1; in a void function
N0216Construct not supported in M1 (string values, member access, qualified types, generic arguments other than truncate<T>; floats and char until M11)truncate<i32, u8>(x)
N0217Not a constant expression, or constant evaluation would panicconst C: u8 = 200 + 100;
N0218Constant depends on itselfconst A: i32 = A + 1;
N0219Invalid main signaturefn main(args: i32)
N0220let without initializerlet a: i32;
N0221var without type annotation or initializervar c;
N0222, N0223(unassigned)
N0224Value of type void used as a valuelet d = nothing();
N0225Expression statement that is not a call1 + 2;
N0226void used other than as a return typevar e: void;
N0227Struct contains itself by value (infinite size); reported at the field that closes the cyclestruct Node { next: Node; }
N0228Duplicate member (field or function) in a structstruct D { a: i32; a: i64; }
N0229Struct literal does not initialise every fieldPoint { x: 1 }
N0230Unknown field (in a literal or an access), or a function named where a field was expectedp.z, p.sum
N0231Field initialised twice in a literalPoint { x: 1, x: 2, y: 3 }
N0232this outside a method, or a this parameter outside a structfn f() -> i32 => this;
N0233Method called as a static function, or a static function called on a valuePoint.sum(), p.origin()
N0234Field access, method call or literal on something that is not a structn.x with n: i32
N0235A block branch of an if or match expression can complete, so it has no value (type-system.md §15.3)let a = if (c) { f(); } else 2;
N0236A closure whose type cannot be inferred: a parameter without a type, or a block body returning a value, where no function or closure type is expected (type-system.md §36.2)let f = (x) => x + 1;

References and borrows (N0240–N0249; lifetimes.md) ​

N0240–N0245 come from the NIR borrow checker. It runs only on programs that type-check, and its errors carry notes ("borrowed here", "the borrow is used later here").

CodeMeaningExample
N0240Assignment to a place while it is borrowed (shared or mutable)let r = borrow x; x = 2; use(r)
N0241Borrow conflicting with a live borrowtwo live borrow mut x, or borrow mut x while borrow x is live
N0242Read of a place while it is mutably borrowedlet m = borrow mut x; print(x); m = 1;
N0243A place or temporary goes out of scope while borrowedlet r = same(five()); use(r)
N0244Returning a reference to a local or temporary (E1)return borrow x; with x local
N0245Return-source errors (E2): missing or invalid borrow(...) list, or a result derived from an unlisted parameterfn f(a: borrow T, b: borrow T) -> borrow T
N0246Reference in a disallowed position: struct field, constant, var local, reference to reference, source list outside a return type. Since M4a this covers every scoped type, scoped results included (type-system.md §19.1)struct S { r: borrow i64; }
N0247borrow of something that is not a placeborrow 5, take(mut five())
N0248borrow mut (or a borrow mut this call) on an immutable placeborrow mut param, shared.grow()
N0249mut argument marker missing or misplacedtake(x) for borrow mut, look(mut x) for borrow

Moves and destruction (N0250–N0259; type-system.md §14) ​

N0212 and N0250–N0253 come from the NIR move checker (since M2c), which also runs only on programs that type-check. A move while borrowed is reported by the borrow checker as N0240.

CodeMeaningExample
N0250Use of a value that was moved (on at least one path), including reading a partially moved struct as a wholeconsume(r); consume(r);
N0251Move out of a place reached through a referencelet a = r.a; with r: borrow Pair and Pair.a a move type
N0252Move of a field out of a value whose type has a drop blockconsume(o.res) with struct Owner { res: Res; drop {} }
N0253Move out of a using bindingusing u = make(); consume(u);
N0254return, break, continue or defer inside a deferred statementdefer return 1;
N0256match that does not cover every value (add the missing variants or _)match (s) { Shape.Empty => { } }
N0257Unreachable match arm: a duplicate pattern, or any arm after _1 => { } 1 => { }
N0258Retired in M3c: a non-Copy payload bound from a value scrutinee now moves out, and the match consumes the scrutinee (type-system.md §18.4)—
N0259Invalid array (type-system.md §16): a length that is not an integer literal from 1 to 2^48 − 1, an element type that is not Copy, or an array larger than 2^31 − 1 bytes; since M9b also copyFrom or fill on a slice whose element type is not Copy (§16.5)[Res; 2], [i32; 0]

Arrays and slices otherwise reuse codes: indexing or slicing a non-array, a non-usize index, or a bad for sequence or range is N0205; writing an element of a let array or through a Slice is N0211; a slice in a field, a var local or an array element is N0246; borrow mut a[..] of an immutable array is N0248; slicing a non-place is N0247. Since M9b, copyFrom or fill on a Slice is N0211, on a slice of an immutable array N0248, and a source that is not a slice of the element type N0205. Slices are references, so the borrow checker reports their conflicts as N0240–N0245.

Region parameters (N0270–N0279; type-system.md §25, M6x) ​

CodeMeaningExample
N0270A scoped field or payload in a struct or enum without region parametersstruct S { v: StringView; }
N0272Storing a value through a borrow mut parameter whose loans the signature does not let flow into itfn put(v: borrow mut Vector<StringView>, s: StringView) { v.push(s)!; }
N0273An unknown region name, region arguments on a type without region parameters, or the wrong number of themStringView<nowhere>, Plain<r>
N0274A generic used with a scoped type argument where it needs an unscoped one (it boxes T, makes an array of T, …)boxed<StringView>(s) with fn boxed<T>(v: T) -> Box<T>

N0271 is unassigned: destroying a value that holds loans while their referents are gone reports N0243.

Unsafe and raw pointers (N0280–N0289; type-system.md §27, unsafe.md, M8a) ​

CodeMeaningExample
N0280An unsafe operation outside an unsafe context: a read, write or arithmetic through a raw pointer, Ptr.toBorrow/toBorrowMut, Slice.fromRaw/SliceMut.fromRaw, a call to an unsafe fn, or a use of a static mut (U1, type-system.md §39.3)let v = p.read(); in a safe function
N0281An invalid raw-pointer pointee: a reference, slice, StringView or other scoped type, or never (a type parameter is allowed since M8d; a scoped argument for it is N0274)*borrow i32, *Slice<u8>
N0282A pointer operation that the pointer or its pointee does not allow: reading or writing a non-Copy type, writing through a *T, toBorrowMut or SliceMut.fromRaw from a *T, any access through *voidp.write(1) with p: *i32; q.read() with q: *void
N0283An unsafe fn, or a function containing unsafe, without a doc comment with a Safety: line (U2)unsafe fn f() {} with no /// Safety: … above it

C interoperability and profiles (N0290–N0299; type-system.md §28, M8b; cosmoos/profiles.md §4, M8c) ​

CodeMeaningExample
N0290An unknown attribute, an attribute in the wrong place or with wrong arguments, a repeated attribute, an ABI other than "C", or an extern declaration with a body, receiver or type parameters; @export on main@inline fn f() {}, @repr(C) enum E { A }, extern "Rust" { … }
N0291A type that cannot cross the C boundary in an extern declaration, an export, or a @repr(C) struct's fieldfn f(s: Slice<u8>); in extern "C", @export fn g() -> Box<i32>
N0292A C name that is not a valid C identifier, is a C keyword (or bool, true, false, NULL, main), is reserved by C, or starts with nova_, nv_, NV_ or nv and an uppercase letter@export("int"), fn nova_alloc(); in extern "C", @repr(C) struct S { default: i32; }
N0293A hosted-only name (Console, Process, File, the heap allocators and every collection or box that needs them, …) or a main function in a package built with --profile freestanding (cosmoos/profiles.md §4.1)Console.writeLine(1);, let b = Box.create(5)!;
N0294An imported C type (type-system.md §31), or a C-laid-out type (§33), used where Nova would need its size or would move it: as a local, parameter, result, field, element, optional or type argument, in a struct literal, or with read, write, add, sub, offset or fromRaw through a pointer; or a borrow of a pointer, usize or isize field of onefn f(i: cosmoboot_info) {}, p.add(1) with p: *cosmoboot_info
N0295An operation whose effect (sleep, alloc) the context forbids: in an @context(atomic) or @context(irq) function, while an @context(atomic) value (a spin-lock guard) is live, or beyond a Nova function's @effects bound (type-system.md §32); a closure body beyond its type's effect list, or a named function with effects its expected function type's list lacks (§36.3)mutex_lock(m) while a SpinGuard is live
N0296A private field named outside the source file that declares its struct: read, assigned, borrowed or given in a literal (type-system.md §12)lock.data outside sync.nova
N0297A float type, literal or fromBits in a build with --no-float (type-system.md §35.9)let x = 1.5; under novac build --no-float
N0298A function that cannot be a function value: an extern or unsafe function, one with region parameters, or main (type-system.md §36.1)let f = puts; with puts declared in an extern "C" block
N0299A closure of the wrong kind: a borrow mut fn where a borrow fn is expected, or a capturing closure where a plain fn is expected (type-system.md §36.2); a function or closure value whose type's effects are not in the expected type's effect list (§36.3)let f: fn(i32) -> i32 = (x) => x + k;

Calling an extern function outside an unsafe context is N0280; two extern declarations or exports with one C name are N0201; CChar as a value type is N0281.

Raw pointers reuse codes: an invalid pointer cast is N0208, ordering comparisons on pointers are N0207, a constant of pointer type is N0216, and an unsafe main is N0219. (An unsafe interface method was N0216 until C5.)

Results and the heap (N0260–N0269; type-system.md §17–§18) ​

CodeMeaningExample
N0260Ok(...) / Err(...) (or, since M4c, Pool.create(...); since M6c, null) without an expected type that fixes its type arguments, or where another type is expectedlet a = Ok(1);, let p = Pool.create(SystemHeap {}, 4u32);, let n = null;
N0261? in a function that does not return a Result with the same error type; ? on an optional in a function that does not return an optional (M6c)? on Result<i32, F> in a function returning Result<i32, E>
N0262? or ! on something that is not a Result or optional value (a reference to one included)n? with n: i32
N0263An allocator argument that is not an allocator type (SystemHeap, FailingAllocator, or for Box since C5 a struct without fields implementing Allocator)Box<i32, Point>, Box.createIn(point, 1)
N0265Type arguments that cannot be inferred: a generic call, struct literal or enum value whose arguments, fields or expected type do not determine every type parameterlet d = Maybe.Nothing;, let e = make();
N0266Generic instantiation nested more than 64 deep (polymorphic recursion)fn deep<T>(x: Maybe<T>) { deep(Maybe.Just(x)); }
N0267An impl that does not match its interface (receiver, parameter or return type, a missing or extra method), a duplicate impl, an impl for a generic or scoped type, an interface method without a receiver, or a method call that two bounds both provideimpl Shape for Square { fn area(this) -> i64 … }
N0268A type argument that does not satisfy a bound of its type parameter (an interface it does not implement, or Copy)total(plain) with fn total<S: Shape>(…)
N0264A type a region cannot hold (R2): one that needs drop, a scoped type, or a non-Copy fill value for allocArrayarena.alloc(Res { id: 1 }), arena.alloc(someReference)

Generic code (M6a) reuses codes:

  • an operator on a type parameter is N0207, a field or method on one is N0234, and a literal for one is N0205;
  • a generic type without its arguments, or with the wrong number of them, is N0204;
  • a duplicate or shadowing type parameter is N0201;
  • a method with type parameters of its own is N0216;
  • a generic main is N0219;
  • naming something that is not an interface as a bound or in an impl is N0204;
  • a method on a type parameter that no bound declares is N0234;
  • an impl method clashing with a type's own method is N0228.

Region values reuse codes:

  • assigning a using binding as a whole is N0211;
  • nesting a frame that is not a using binding is N0248;
  • a method call on a frame that is not a local is N0247;
  • a storage that is not [u8; N] or SliceMut<u8> is N0205;
  • returning a frame or fixed-buffer allocator without sources is N0245.

? inside a deferred statement is N0254, and Ok/Err with the wrong number of values is N0209. The names Result, Ok, Err, AllocError, Box, SystemHeap and FailingAllocator cannot be declared (N0201). Moving out of a box's contents is N0251 until M3c.

Build (N0300–N0399) ​

CodeMeaningExample
N0300novac build --emit exe without a main functiona library-only file

Names across packages (N0310–N0319; type-system.md §2, ADR 0013):

CodeMeaningExample
N0310The package named in an import, or in a struct literal p.T { … }, is not a dependency of the package (elsewhere an unknown p in p.x is N0200)import geometri;
N0311A dependency has no item of that namegeometry.Pointt
N0312The item exists but is not public, or a field or method of a public struct is notgeometry.helper() with fn helper internal
N0313A simple name is provided by two importsimport a; import b; both with Point, then Point
N0314A public item's signature names a type that other packages cannot seepublic fn make() -> Hidden with struct Hidden internal
N0315An item, parameter, local, loop variable or pattern binding has the name of one of the package's dependencieslet geometry = 1;

Packages (N0320–N0329; tooling.md §4, ADR 0013):

CodeMeaningExample
N0320nova.toml or nova.lock is not valid in the TOML subsetname = app (no quotes)
N0321A manifest field is missing, unknown or invalid, or a dependency is an executablekind = "binary"
N0322A path dependency's directory or manifest is missing, or its name differs from its keygeometry = { path = "../geo" } with no ../geo/nova.toml
N0323A git dependency cannot be fetched or resolved, or is absent with --offlinean unknown tag
N0324The lock file is missing or does not match the manifesta dependency added without novac fetch
N0325A git checkout's manifest and sources do not match the lock's hasha file edited in the cache
N0326One package name reached through two different sourcestwo paths to two geometry packages
N0327A dependency cyclea depends on b, b on a
N0328An invalid version, version requirement, or index entry (tooling.md §4.6)shapes = "1.x"
N0329No versions satisfy the requirements: the conflicting requirements and where each came from (§4.7)^2.1 (from geometry 1.4.0) and ^1.0 (from plot 0.3.0)
N0335novac publish: the package cannot be published as it is (§4.8)a path dependency, or uncommitted changes

Dynamic dispatch and owning closures (N0330–N0339; type-system.md §37, §36.5, ADR 0015):

CodeMeaningExample
N0330dyn I where it is not behind a reference or a Box: a local, parameter, field, element, optional or type argumentfn f(s: dyn Shape), Vector<dyn Shape>
N0331dyn I for an interface that is not dyn-compatible: one of its methods takes this by valueinterface Sink { fn close(this); } then borrow dyn Sink
N0332A move literal captures a scoped value: a reference, view, slice, closure, or a value with region parameters (type-system.md §36.5)let v = s.view(); Box.create(move () => v.length)
N0333A move literal anywhere but as the value of Box.create/createIn with an expected Box<dyn fn…>let f = move (x: u64) => x;
N0334A value that is not Send where it must cross to another thread: a spawned closure's capture or result, a dyn … + Send coercion's source, a Send bound's argument, or, for Thread.both, a capture that may not be used from two threads at once or an argument that is not a closure literal or fn() value (type-system.md §38, §38.6)Thread.spawn(move () => view.length) with view: StringView
N0336@effectsOf that names no parameter, or a parameter that is not of a function or closure type, or has no names (type-system.md §32.5)@effectsOf(n) with n: i32; @effectsOf()
N0337A static that cannot be one: a static whose type is not Share, or a generic or local one (type-system.md §39)static C: Cell = … with Cell not Share
N0338Not a static initialiser: an initialiser or @constant body outside §39.4, or a C constant macro called elsewherestatic N: u64 = compute();

Pre-1.0: the language and its tools are still changing.