Skip to content

Error codes

Every compiler error includes a code like [E0100]. Run yonac --explain E0100 to see a detailed explanation with examples for any code on this page. See the Compiler CLI reference for warning-control flags.

Two types that should be compatible are not.

# Error: Int and String cannot be unified
1 + "hello"
# Fix: ensure both operands have the same type
1 + 2

Common causes:

  • Operator applied to incompatible types (Int + String)
  • If branches return different types (if true then 1 else "no")
  • Function called with the wrong argument type
  • Sequence with mixed element types ([1, "two", 3])

Constructor diagnostics include the constructor name, declared field shape, and the specific field mismatch. A tuple annotation is one constructor field, so preserve that nesting in the pattern:

type Box = Box (Int, Int)
# Error: two constructor fields were written for one tuple field
case Box (1, 2) of Box (first, second) -> first end
# Fix: match the single field with a tuple subpattern
case Box (1, 2) of Box ((first, second)) -> first end

A type variable would need to contain itself (occurs check failure). This happens when an expression’s type depends on itself circularly.

# Error: f's type would contain itself
let f x = f in f

Fix: break the self-reference; a function cannot be its own return type.

A tuple pattern has a different number of elements than the tuple being matched.

# Error: 3-tuple matched against 2-tuple pattern
case (1, 2, 3) of (a, b) -> a end
# Fix: match all elements
case (1, 2, 3) of (a, b, c) -> a end

A variable is used but not defined in the current scope. The compiler suggests similar names when a close match exists:

error: undefined variable 'lenght'; did you mean 'length'? [E0103]
# Variables are only visible within their defining scope
let x = 42 in x # OK
x # Error: x is not in scope

Fix: correct the spelling or bind the variable before use.

A function is called but has not been defined or imported.

error: undefined function 'prnt'; did you mean 'print'? [E0104]

Fix: correct the typo or add the missing import.

A trait method is called on a type that doesn’t implement the trait.

# Error: no instance for 'Num String'
abs "hello"
# Fix: use a type that has a Num instance
abs (-42)

A trait is used but no instances have been registered for it at all. This usually means the trait definition is missing or not imported.

Fix: define or import the trait and at least one instance.

See effects for the effect system itself.

A perform calls an effect operation, but no handle ... with block in scope provides a handler.

# Error: no handler for State.get
perform State.get ()
# Fix: wrap in a handle block
handle
perform State.get ()
with
State.get () resume -> resume 42
return val -> val
end

A perform call passes the wrong number of arguments to an effect operation.

# Effect declares: put : s -> ()
# Error: put expects 1 argument, got 0
perform State.put
# Fix: pass the required argument
perform State.put 42

A function whose type includes latent effects (!{Effect.op}) is applied where those operations are not covered by a surrounding handle ... with. The primary diagnostic points at the introducing perform; a note marks the application that lets the effect escape. Independent callback effects are reported separately, but pure curried partial applications do not repeat an operation before the final source application runs.

# f : a -> !{State.get} Int
let f = (\x -> perform State.get ()) in
f 0 # Error: points at `perform State.get`
# Fix: handle the effect at the use site
handle f 0 with
State.get () resume -> resume 7
end

A direct perform without a handler still warns via -Wunhandled-effect.

E0203 — Effect-freedom requirement not satisfied

Section titled “E0203 — Effect-freedom requirement not satisfied”

yonac --require-effect-free accepts only a closed empty effect row, exhaustive registered finite-ADT and Bool case expressions, and a sound structural size-change proof for every local recursive SCC. Direct and mutual recursion can be accepted, including lexicographic descent over multiple parameters. Proof facts come from structural fields or non-empty sequence tails bound by unguarded patterns; simple lexical aliases preserve them.

Known operations, open row variables, imports without row facts, missing alternatives, numeric decreases, guarded descent, opaque/helper or higher-order recursion, incompatible-arity SCCs, mixed incompatible cycles, and every other unproved recursive cycle are rejected. A proven empty exported row is recorded in .yonai as effects -.

The flag is not a general termination checker and does not prove arbitrary open-domain coverage. Ordinary compilation remains unchanged; for example, --Wincomplete-patterns can warn about missing alternatives. Strict E0203 validation is CLI-only today because yls and the VS Code and Zed integrations do not expose --require-effect-free; ordinary diagnostics remain shared.

The parser encountered a token that doesn’t fit the expected syntax. Common causes:

  • Missing closing bracket, paren, or end keyword
  • Extra comma or semicolon
  • Reserved word used as an identifier

The source code doesn’t match any valid Yona syntax. Check expression structure and keyword spelling against the language specification.

A pattern in a case expression or function parameter is malformed. Valid pattern forms:

42 # integer literal
"hello" # string literal
:ok # symbol
x # variable binding
_ # wildcard
(a, b) # tuple
[h|t] # head-tail (list)
[] # empty list
Some x # constructor
(n : Int) # typed (sum type)
p1 | p2 # or-pattern

LLVM could not produce an object file. This is usually an internal compiler error.

The system linker failed to produce an executable. Common causes:

  • Missing canonical runtime archive (yona_runtime.lib on Windows or libyona_runtime.a on Unix)
  • Undefined symbols from missing module imports
  • System linker not installed

Fix: check that the toolchain is installed and imported modules have been compiled; see the Compiler CLI reference for YONAC_CC and --linker-mode.

The codegen encountered an AST node it cannot compile. This may indicate a language feature that is not yet implemented.

A field access or update refers to a field name that doesn’t exist on the ADT.

type Person = Person { name : String, age : Int }
p.email # Error: 'email' is not a field of Person
p.name # OK

The pipe operator (|> or <|) requires a function on the receiving side.

# Error: 42 is not a function
"hello" |> 42
# Fix: pipe into a function
"hello" |> length

E0500 — Refinement predicate not satisfied

Section titled “E0500 — Refinement predicate not satisfied”

A function expects a refined type, but the compiler cannot prove that the argument satisfies the refinement predicate.

type NonEmpty a = { xs : [a] | length xs > 0 }
head : NonEmpty a -> a
# Error: cannot prove 'someList' is non-empty
head someList
# Fix: establish the fact via pattern matching
case someList of
[h|t] -> head someList # OK: [h|t] proves non-empty
[] -> defaultValue
end

Passing a literal that obviously satisfies the predicate (e.g. head [1, 2, 3]) also works, as does a pattern match or comparison that proves an integer refinement such as { n : Int | n > 0 && n < 65536 }.

These are produced by the linearity checker for Linear values (see the Prelude).

A linear value was used after it was already consumed by a pattern match or function call.

let conn = Linear (tcpConnect host port) in
case conn of Linear fd -> close fd end # conn consumed
send conn "hello" # Error: already consumed

Fix: use the value before consuming it — do all work inside the case arm that unwraps it.

A linear value is consumed in one branch of an if/case expression but not the other. Both branches must consume the same linear values.

# Error: conn consumed in then-branch but not else-branch
if ready then
case conn of Linear fd -> close fd end
else
() # conn still live here

Fix: consume the value in every branch (e.g. close it in the else branch too).

A linear value went out of scope without being consumed. This likely means a resource (file, socket, process) is leaked. Emitted as E0602 under -Wlinear-leak (on by default; --Wno-linear-leak suppresses; --Werror promotes it).

let conn = Linear (tcpConnect host port) in
42 # Warning E0602: conn never consumed

Fix: consume the value via pattern match before the end of its scope.

@borrow marks a parameter as read-only for the function body: it must not be returned, stored in a collection literal, captured by a nested lambda, or used as a case scrutinee (head/tail consumes the sequence). It is only supported on simple identifier parameters.

# Error: borrowed parameter is returned
let f @borrow s = s in f

Fix: remove @borrow, or change the body so the parameter is only read.

Only reported under yonac --strict-accelerator, which requires Std\IntArray / Std\FloatArray map / filter / foldl lambdas to match the fixed Std\Gpu kernel library (x + k, x * k, x > k, sum, float scale). Arbitrary lambdas such as \x -> x * x are not compiled to SPIR-V; without the flag they stay on the correct host closure path, while with it they are a hard error so GPU expectations cannot silently diverge from the fixed-kernel ABI.

Fix: rewrite the lambda as a fixed kernel (e.g. map (\x -> x + 1), explicit mapGpu), or drop --strict-accelerator to keep the host path.

Warnings are controlled via --Wall, --Wextra, -w, and --Werror (see the Compiler CLI).

Flag Name --Wall --Wextra
-Wunused-variable Unused variable binding yes yes
--Wincomplete-patterns Non-exhaustive finite-ADT or Bool pattern match yes yes
--Woverlapping-patterns Later arm provably covered by earlier unguarded arms yes yes
-Wunhandled-effect perform without matching handle yes yes
-Wlinear-leak Unconsumed Linear value at scope exit (E0602; on by default) yes yes
-Wshadow Variable shadowing no yes
-Wmissing-signature Function without type annotation no yes
-Wunused-import Imported name not used no yes