Troubleshooting
Look up a problem by what you see, or by the diagnostic code. Every program below is checked against the real toolchain when the documentation is tested, so the code each one produces is the code shown. The complete code tables are in the checker notes, the runtime notes, and the AST reference.
Tools should match on the code, never on the message. Read the first diagnostic first: a later one is often a consequence of it. A syntax error is reported alone.
By symptom
oskac run prints diagnostics and exits with 1
oskac run checks the program first and refuses to run it if the check reports anything. Run oskac check file.osk to see the same diagnostics with the authority report. Exit code 1 also means main returned Err; in that case the message is the error's Display text and no error[...] line appears.
oskac run exits with 2 and runs nothing
The program uses something the interpreter cannot run yet, and oskac says so before running any of it: E0370 for the capabilities Net, NetConnect, NetListen, Spawn, and Sched, E0371 for the modules std.sql and std.proc, and E0380 for a few constructs. The program may still pass oskac check. See what the runtime refuses.
oskac run exits with 101
The program panicked, which means it has a bug. The last line on standard error has a P code, a message, and the byte range of the expression that panicked. See debugging.
My dbg output is missing from a pipe or a file
dbg writes to standard error, not standard output. Redirect with 2>&1, or read standard error.
The program cannot read a file that exists
A directory capability refuses an absolute path, an empty path, a path that climbs out with .., and any path that goes through a symlink, whether the link points outside the root, inside it, or nowhere. On Linux and macOS it also refuses an existing file with more than one hard link. The refusal is an Err(IoError), not a panic, so the program sees Err. Check the directory you passed to restrict_to, and that the path is relative to it. See attenuation.
The checker says Fs, FsRead or FsWrite cannot read or write (E0273)
Since v0.2.0 these three capabilities only attenuate: read_to_string, list_dir, write, and create_dir are gone from them. Narrow to a directory first, and call the method on the result: fs.restrict_to("<root>").read_to_string(path). For one file, use restrict_to_file("<file>") and call read_to_string() or write(text) with no path. Code that must reach anywhere writes restrict_to("/"). See attenuation and upgrading to v0.2.0.
env.secret panics with P0020
The variable is not set. A secret has no stand-in value, so that a missing password can never become an empty one. Set the variable, or use env.get, which returns an Option.
A constant cannot be used
A module-level const NAME: T = expr declares and checks, but referring to NAME reports E0221 in this release. Pass the value as a parameter, or write it in a function body.
{self.name} inside a string is an unknown name
An interpolation hole that starts with self reports E0221 in this release. Copy the field into a local with let, and interpolate the local.
A type misspelled in a let annotation is not reported
In a signature, an unknown type is E0200 with a "did you mean" fix. In a let annotation inside a body, this release does not report it. Do not rely on a clean check to confirm a type name in a body.
A contract that is violated stops the program
requires and ensures are evaluated on every call, in every build. A false requires panics with P0006 at the call, and a false ensures panics with P0007 at the clause. A program whose contracts were silently false in v0.1.0 now panics. Fix the caller for P0006 and the function body for P0007, or correct the contract if it was wrong. For a failure you expect, such as bad user input, validate with an explicit if and return a Result instead, because a panic cannot be caught.
oskac is not found
After a source build, put target/release/oskac on your PATH. After an installer, put ~/.oska/bin on it.
By code
Syntax: E00xx and E01xx
A syntax error is reported alone. Newlines end statements, and there is no ;.
E0005, a ; at the end of a line. The fix removes it.
fn main(io: Stdout) -> Result<(), IoError> {
io.println("hi");
Ok(())
}
E0102, a string interpolation that holds more than a name or a field path. Compute it with let first.
fn main(io: Stdout) -> Result<(), IoError> {
io.println("total {1 + 2}")
}
E0104, a let or var without an initializer. Write let x: Int = 0.
fn main() {
let x: Int
}
E0120, fields or variants not separated by commas, even on separate lines. The fix inserts the comma.
struct Point {
x: Int
y: Int
}
E0143, a comma after a match arm. Arms are one per line, with no commas. The fix removes it.
fn flip(b: Bool) -> Int {
match b {
true => 1,
false => 0
}
}
E0140, an or-pattern such as A | B. This release has no or-patterns, range patterns, or @ bindings (E0141, E0142). Write one arm for each.
fn small(n: Int) -> Bool {
match n {
1 | 2 => true
_ => false
}
}
E0001, a character that is not part of the language, such as $. E0002, an unterminated string.
Names and types: E020x and E022x
E0200, an unknown type. The fix suggests the closest declared name.
fn shout(text: Strng) -> Int {
1
}
E0220, a type mismatch. There are no implicit conversions, so convert explicitly.
fn main() {
let n: Int = "four"
}
E0221, an unknown name. The fix suggests the closest local, function, or variant. A capability you did not declare is this error, and so is a const.
fn main(io: Stdout) -> Result<(), IoError> {
io.println(greeting)
}
E0223, an operator that does not apply to its operands. + works on numbers only, so build text by interpolation.
fn join(a: String, b: String) -> String {
a + b
}
E0224, the wrong number of arguments. E0228, an unknown method, variant, or associated function, with a "did you mean" fix. E0227, an unknown field.
fn main() {
let xs: List<Int> = List.new()
let n = xs.length()
}
E0233, a type the checker cannot infer. Add an annotation.
fn main() {
let xs = List.new()
}
E0265, a type that does not implement a needed trait. A common case is interpolating a Bool, which has no Display. Use if and print a message for each case.
fn main(io: Stdout) -> Result<(), IoError> {
let ready = true
io.println("ready: {ready}")
}
Mutation and results: E0229, E023x, E024x
E0229, assigning to something that is not a var. The fix changes let to var.
fn main() {
let count = 0
count = count + 1
}
E0230, calling a mutating method on a let binding.
fn main() {
let items: List<Int> = List.new()
items.push(1)
}
E0240, a dropped Result. Handle it, propagate it with ?, or discard it on purpose with let _ = f().
fn main(io: Stdout) -> Result<(), IoError> {
io.println("hi")
Ok(())
}
E0242, ? on a Result whose error type is not the function's, with no impl From to convert it. E0243, ? in a function that does not return the same kind, such as an Option in a function returning Result. Convert with .ok_or(err)?.
fn first(xs: List<Int>) -> Result<Int, String> {
let head = xs.get(0)?
Ok(head)
}
Patterns: E025x
E0253, a match that is not exhaustive. The message lists the missing patterns, and the fix adds an arm for each, with todo() as its body.
fn name(b: Option<Int>) -> String {
match b {
Some(n) => "some"
}
}
E0254, an arm that can never match because an earlier one covers it. E0250, a pattern that names no variant, such as a misspelled Nnoe: an uppercase name in a pattern is always a variant.
Capabilities: E021x, E027x, E028x
E0210, a struct that holds a capability but is not declared cap. The fix inserts cap.
struct Logger { out: Stdout }
E0211 and E0212, a main with a parameter that is not a built-in capability or Args, or a return type other than () or Result<(), E> with E implementing Display.
fn main(name: String) {
}
E0217, a main that declares a directory or file capability (Dir, DirRead, DirWrite, FileRead, FileWrite). Only attenuation makes one, so declare Fs, FsRead, or FsWrite and call restrict_to or restrict_to_file.
fn main(docs: DirRead) {
}
E0273, a call of read_to_string, list_dir, write, or create_dir on Fs, FsRead, or FsWrite. These only attenuate. The message shows the fix: narrow first, as in fs.restrict_to("<root>").read_to_string(path).
fn main(fs: FsRead) -> Result<(), IoError> {
let _ = fs.list_dir(Path.new("."))?
Ok(())
}
E0270, a closure that captures a capability passed where a plain fn is expected. Declare the parameter cap fn. E0271, forging a capability. E0280, a contract that calls a function with a capability. See capabilities. A contract in the wrong place or form is E0218 (on a method of impl Trait for Type: move it to the trait), E0219 (on main), or E0282 (a ? or return directly in the condition).
Trust, sinks, and secrets: E03xx
E0300, untrusted text where trusted String is required. Check it with a validator, or vouch for it with .assume_trusted(), which is an audit site.
fn open(name: String) -> Int {
name.len()
}
fn main(args: Args) {
let who = args.get(1).unwrap_or("x")
let n = open(who)
}
E0310, a sink literal whose module is not imported. The fix inserts the use.
fn query() {
let q = sql"SELECT 1"
}
E0341, text where a sink literal is required. SQL cannot be built from text. E0350, E0351, and E0352, a Secret interpolated, compared with ==, or printed. See untrusted data and secrets.
Release builds: E0216 and E0293
oskac check --release rejects dbg(...) and todo():
fn main(io: Stdout) -> Result<(), IoError> {
let n = dbg(1)
let m: Int = todo()
io.println("done")
}
main.osk: error[E0216]: `dbg(...)` is not allowed in a release build (bytes 57..63)
fix: remove `dbg`, keeping its argument
main.osk: error[E0293]: `todo()` is not allowed in a release build; finish this code first (bytes 81..87)
Runtime: E0370, E0371, E0380, and P codes
These come from oskac run and oskac test, not from oskac check. The refusals have exit code 2. The panics have exit code 101, and under oskac test they fail only their own test. See debugging for the panic table.
Getting the explanation from the toolchain
oskac explain <code> prints the catalog entry for a diagnostic code offline: what it means, a program that fails with it, and the same program fixed. The documentation site has the same entry as one page per code at /codes/E0300, and all of them as data in /codes.json. See the CLI reference.
oskac explain E0300