Reference
Diagnostics
The compiler talking, captured by compiling a program per entry rather than transcribed.
The compiler can emit 144 distinct codes. 13 of them are catalogued here, across 2 families, and every one was produced by compiling the program shown above it rather than transcribed from the source.
That distinction matters more than it sounds. A message is built where it is raised, from the name it is about, so a transcribed catalogue would be a template with a hole in it and would go stale the first time anybody reworded one. A snippet here that stops producing the code it is filed under fails the build.
DS0201 resolution and types
// Writing through a parameter that is not `mut`.
//
// Mutability sits on the parameter rather than on the type, so a signature says which of its
// arguments it may write and the compiler holds it to that.
data Door {
open: bool = false
}
fn shut(door: Door) {
door.open = false
}
DS0201.drs:11:5 DS0201 `door` is not declared `mut`, so it cannot be written through
door.open = false
^^^^^^^^^
DS0205 resolution and types
// A name that is not defined.
//
// Functions may be called before they are declared, so declaration order carries no meaning and
// this is genuinely a missing name rather than one that arrives later in the file.
fn go() -> f32 {
return missing(1)
}
DS0205.drs:7:12 DS0205 `missing` is not defined.
return missing(1)
^^^^^^^
DS0210 resolution and types
// Deliberately refused.
//
// A `match` must cover every variant, and the error names the ones it missed rather than saying
// "not exhaustive", which is the answer you were about to go and look up. `Amber` is missing here,
// and the alternative to this error is a run-time surprise on the one afternoon the light is amber.
enum Light {
Red
Amber
Green
}
fn go(light: Light) -> bool {
return match light {
Red => false
Green => true
}
}
exhaustive.drs:14:12 DS0210 this `match` does not cover `Amber`
return match light {
^^^^^^^^^^^^^^^^^^^^^^^^
DS0226 resolution and types
// `Ok` with nothing to say what the error type is.
//
// `Ok` and `Err` take their other half from context: the binding's annotation or the function's
// return type. With neither, this is an error rather than a guess.
fn go() {
let a = Ok(1)
}
DS0226.drs:7:13 DS0226 `Ok` needs a `Result` type from its context — annotate the binding or the function's return type
let a = Ok(1)
^^^^^
DS0228 resolution and types
// A record literal that leaves a field out.
//
// Leaving one out is an error rather than a silent fill from the declared default. A literal that
// looks complete while half of it came from somewhere else is the same ambiguity as an implicit
// null, one level up. Defaults are for the generated `createDoor()`, which is a different
// operation with a different name.
data Door {
open: bool = false
angle: f32 = 0
}
fn make() -> Door {
return Door { open: true }
}
DS0228.drs:14:12 DS0228 `Door` needs a value for `angle`
return Door { open: true }
^^^^^^^^^^^^^^^^^^^
DS0230 resolution and types
// Deliberately refused.
//
// There is no implicit widening. The compiler names the conversions rather than guessing which
// one was meant, because the guess is where a value quietly changes width.
fn add(a: u8, b: u32) -> u8 {
return a + b
}
widening.drs:7:12 DS0230 `+` needs both operands to be the same type, but found `u8` and `u32`. There is no implicit widening; convert one explicitly with `checked`, `clamp` or `wrap`.
return a + b
^^^^^
DS0231 resolution and types
// A wrapping operator on a float.
//
// `+%` and `+|` need an integer. On an `f32` this is an error rather than a synonym for `+`,
// because floats neither wrap nor saturate, and accepting it would teach that the distinction is
// decorative.
fn add(a: f32, b: f32) -> f32 {
return a +% b
}
DS0231.drs:8:12 DS0231 `+%` is wrapping or saturating arithmetic and needs an integer, but this is `f32`
return a +% b
^^^^^^
DS0251 resolution and types
// A function that can finish without returning.
//
// A function declaring a return type must return on every path. A trailing `if` without an `else`
// is an error, because the path where the condition is false reaches the end.
fn pick(on: bool) -> f32 {
if on {
return 1
}
}
DS0251.drs:6:1 DS0251 `pick` declares `f32` but can finish without returning
fn pick(on: bool) -> f32 {
^^^^^^^^^^^^^^^^^^^^^^^^^^
DS0254 resolution and types
// Deliberately refused.
//
// A bare value does not flow into an option position. `return 1` from a function returning `f32?`
// is an error, and `return some(1)` is what was meant. A language that accepted the first has
// reinvented implicit null in the other direction: a reader can no longer tell an absence that
// was decided from one that was never filled in.
fn find(present: bool) -> f32? {
if present {
return 1
} else {
return none
}
}
option.drs:10:16 DS0254 this function returns `f32?` but this is `f32`
return 1
^
DS0255 resolution and types
// Deliberately refused.
//
// There is no truthiness. A condition must be `bool`, and the fix is to say what you meant:
// `if count != 0`.
fn ready(count: u32) -> bool {
if count {
return true
} else {
return false
}
}
truthiness.drs:7:8 DS0255 a condition must be `bool` but this is `u32`. There is no truthiness in this language; compare explicitly.
if count {
^^^^^
DS0263 resolution and types
// Deliberately refused.
//
// A `List<Wolf>` is not a `List<Dog>`, even though a `Wolf` is a `Dog`. With covariance the call
// below would hand `adopt` a reference whose real list holds wolves, and pushing a plain `Dog` into
// it would put one in a list every reader believes is wolves.
//
// Record subtyping is sound in this language partly because that cannot happen: a record is read
// through its fields and a list can be written through.
//
// `:` before the brace is the base clause. It is not a new keyword, and a reader meets `:` here
// meaning "extends" and three lines later meaning "has type"; the position is what keeps the two
// apart, since a type annotation never follows a record's name.
data Dog {
weight: f32
}
data Wolf: Dog {
pack: u32
}
fn adopt(kennel: mut List<Dog>, arrival: Dog) -> u32 {
push(kennel, arrival)
return len(kennel)
}
fn release(pack: mut List<Wolf>, stray: Dog) -> u32 {
return adopt(pack, stray)
}
invariance.drs:28:18 DS0263 `adopt` expects `List<Dog>` for `kennel` but this is `List<Wolf>`
return adopt(pack, stray)
^^^^
DS0288 resolution and types
// A system that writes a component it did not say it writes.
//
// `reads` and `writes` are assertions rather than documentation: the compiler works out what a
// system touches, following the functions it calls as well as its own body, and refuses a
// declaration that leaves a write out. The name of the system and the name of the component are
// both in the message, so the fix is where the reader is already looking.
//
// A declaration wider than the body is a warning instead, because claiming more than you touch is
// sometimes deliberate and costs only a scheduler that keeps two systems apart.
component Hunger {
value: f32 = 0
}
system Feeder {
reads Hunger
update {
for who in query<Hunger>() {
who.Hunger.value = who.Hunger.value + 1
}
}
}
undeclared-write.drs:15:1 DS0288 `Feeder` writes `Hunger` and does not declare it. Add `writes Hunger`, or the engine refuses the write when the system runs.
system Feeder {
^^^^^^^^^^^^^^^
DS0301 linking
// A module the target does not provide.
//
// This is the language's thesis as a single diagnostic. The file parses and type-checks; only
// linking declines it, and the refusal names the module, the target, and whether the capability
// exists in this host at all. That is what lets a file be written against a capability which has
// not shipped, and link unchanged on the day it does.
//
// This snippet named `drift/navigation` until 2026-08-28, when the engine provided it and this
// example stopped producing its own diagnostic. It named `drift/network` until 2026-09-03, when
// Track J provided that one and it happened again. The thesis demonstrating itself twice, which is
// a better argument than the paragraph above: nothing in the file changed either time, and it
// compiled on the day the host caught up.
//
// It named `drift/xr` until 2026-09-05, when Track I provided that one and it happened a third
// time. That was the last: this engine now describes every module the language specifies, so there
// is no unprovided surface left to point at and this snippet cannot be re-aimed again.
//
// So the target is what withholds the module now, rather than the engine being behind. That is the
// case a reader is actually in: a host chooses which capabilities its target manifest carries, and
// a file naming one it left out is refused with exactly this diagnostic. The demonstration is the
// same and it no longer depends on this engine having a hole.
import { session } from "drift/xr"
fn go() -> f32 {
return 1
}
DS0301.drs:23:1 DS0301 `drift/xr` is not provided by target `driftengine`. The module is specified and your file is valid: add it to the target manifest if this host provides it, or it links when a host implements it.
import { session } from "drift/xr"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^