Diagnostics Directory

Reading a diagnostic

Every message follows one shape: a short code, a plain sentence, a pointer at the exact column, and a fix hint. Reference to an undeclared name produces:

text
┌─ error[E303]: undefined variable `nosuchvar`
│  src/main.rnx:1:26
│
│   1 │  fn main(): Int { let x = nosuchvar + 1; return x; }
·     │                           ▲
│
└─ note: declare the variable with `let` or check the spelling

Inside-out, the box states:

  1. The code — E303. Codes starting with E are errors (exit 1); W codes are warnings (exit 0 unless --deny-warnings). Codes are stable across releases: they are searchable on this page, expandable with rnx explain E303, and matchable in CI with rnx check --json.
  2. The message — one sentence naming the problem in program terms, never compiler internals.
  3. The location — file, line, and column, with a source excerpt and a ▲ pointer under the exact column.
  4. The note — the fix: what to type next.

Warnings print in yellow without failing the build. Fatals (fatal: ...) report runtime stops — traps and failed assertions — in the same box shape with the function and span where execution stopped. Uncaught throws print as Uncaught exception: <value> on stderr with a Stack trace: section naming the stop site instead of a box. Errors stop the pipeline; when several appear, the first is fixed first, since later errors are frequently downstream echoes.

rnx explain expands any code into full text plus fix:

sh
rnx explain E303
text
E303: undefined variable
fix: declare the variable with `let` or check the spelling

Lexical codes (E005)

CodeSeverityCauseResolution
E005errorremoved :: syntax (paths, variants, generics use . and <>)replace :: with .

Module and declaration codes (E105-E112)

CodeSeverityCauseResolution
E105errorfn(...) => ... lambda form; fn declares named functions with block bodies onlyuse (params) => body for lambdas
E107errorcircular package dependency; reserved for external package graphs, never emitted for intra-project file importsbreak the dependency cycle between packages
E108errorgeneral compile error: single-statement if bodies holding declarations, pub signatures with non-C-compatible types, missing operator hooks, unknown packages, and related structural violationsread the message; it names the exact rule (declarations need { ... }, hooks name the operator and type)
E109errorawait outside an async fn (entry-file top level is exempt)move the await into an async fn or to the entry file top level
E110errorC-style for (init; cond; step)use for x in range or while
E111errordirect .poll() call; the polling model is retireduse await or promise.wait() instead
E112errorloose top-level statement or top-level await in an imported modulemove execution logic into a function or class method; top-level statements live in the entry file only

The E108 declaration rule, corrected:

.rnx
let x = 1;
if x > 0 {
    let y = 2;
    print(y);
}

Boundary codes (E201-E204)

CodeSeverityCauseResolution
E201errorcall to an unsafe fn outside an unsafe blockwrap the call in unsafe { ... }
E202erroraddress-of (&x) or Pointer arithmetic outside unsafemove the operation into an unsafe block
E203errorprivate field, method, or module item accessed outside its scopewiden visibility or access through the owning scope
E204errorclass invoked as a direct call (Meter(20)) instead of newinstantiate with new Meter(20)
.rnx
class Meter {
    let v: Int;
    init(v: Int) { this.v = v; }
}

let m = Meter(20);

The direct call fails with E204; new Meter(20) is the fix.

Binding codes (E205-E206)

CodeSeverityCauseResolution
E205errorassignment type mismatch: the value type is not assignable to the variable typedeclare the variable as Any for dynamic reassignment, or use T? for nullable bindings
E206errorlet/const without an initializeradd = <expr> (reported instead of E108, with recovery on ;)
.rnx
let count: Int = 0;
count = "forty-two";

The reassignment fails with E205: a String is not assignable to an Int binding. Declaring the variable as Any is the fix.

.rnx
let count: Any = 0;
count = "forty-two";

A const declared without an initializer fails with E206.

.rnx
const limit: Int;

Adding the initializer is the fix.

.rnx
const limit: Int = 10;

Type and ownership codes (E302-E305)

CodeSeverityCauseResolution
E302errorintra-procedural ARC cycle without escaperestructure so the value escapes, or route the back-edge through GenRef
E303errorreference to a value name with no visible declaration; applies to lowercase-led names only (PascalCase names are type references that single-file checks leave alone)declare with let or correct the spelling
E304errorreturn value does not match the declared return type, with expected/got labelsalign the returned value with the signature
E305errorimplicit Float/FastFloat mix in one expressionconvert explicitly with .asFast()/.asStrict()
.rnx
let strict: Float = 0.5;
let fast = strict.asFast();
print(fast * 2.0.asFast());

Packaging codes (E402, E501)

CodeSeverityCauseResolution
E402errorschema mismatch in a typed file: importalign the import schema with the file
E501errorpublish attempted without a publisher tokenpass --token <token> or set RNX_TOKEN

Security codes (S101-S501)

Capability and permission failures. The full model — capability grammar, [permissions] ceilings, tiers, and the rnx audit / rnx lock workflow — is specified in Project and Toolchain.

CodeSeverityCauseResolution
S101errorcapability mismatch: deduced capabilities exceed the Project.deplock ledgerapprove the capability and re-lock, or remove the offending use
S102errorpermission ceiling exceeded: a capability outside [permissions] allowednarrow the package code or deliberately widen the ceiling
S201erroruntrusted path mutation: a delegated argument modified before reaching a sinkpass the delegated value through untouched or request the ambient grant
S301runtime trapprotected path violation: dependency code targeting Project.config, Project.deplock, .git, or cache dirsnever target those paths from dependency code; the abort is the intended enforcement
S401runtime trapunapproved child process executionadd a covering sys:exec:<name> grant with explicit approval
S501errorcapability analysis timeoutsplit the package into smaller modules; never skip the scan

Cycle warnings (W104-W109)

CodeSeverityCauseResolution
W104warningself-capturing closure without decaycapture GenRef(this) with fn decay(this)
W108warningmutual strong fields A<->Bconvert one side to GenRef
W109warning#[Allow(CyclicReference)] field never cleared to nullclear the field in deinit or a clear*/close*/reset* method

Manifest warnings (W201)

CodeSeverityCauseResolution
W201warningunrecognized manifest section or field; ignoredcorrect the spelling or remove the entry

Lint rules (L001-L005)

rnx lint reports these as warning[L00N] findings; --deny-warnings promotes them to build failures for CI.

CodeMeaning
L001let/const never read (_ prefix silences)
L002function or method parameter never used (_ prefix or empty trait methods exempt)
L003statements after return, throw, break, or continue
L004pub fn/class/struct/trait/enum without /** */ docs
L005empty {} in if, while, defer, try, or unsafe blocks

Summary

  • Every diagnostic is code plus sentence plus ▲ pointer plus fix note; codes are stable and CI-matchable.
  • Errors fail the build, warnings advise, fatals report runtime stops.
  • rnx explain <code>, editor hovers, and rnx check --json expose the same registry to humans and scripts. explain covers every E, W, and S code; the L001-L005 lint rules below are documented in their table and fixed per row rather than through explain.