Compiler diagnostics
Every compile error has a stable code. A code never changes meaning once released. Each entry below gives the cause, an example that produces it, and a fix. The same text is built into the compiler:
lucid explain E0303lucid explain --json E0303The ranges are: E00xx files, E01xx lexer, E02xx parser, E03xx names and types, E09xx compiler limits and features not built yet. Codes never change meaning once released.
The examples on this page are wrong on purpose: each one produces its own code.
E0001: Cannot read the file
Section titled “E0001: Cannot read the file”The path does not name a file that can be read, or names a directory with no lucid.toml at or above it.
Fix: check the path, and run from the directory that the path is relative to.
E0002: File is not valid UTF-8
Section titled “E0002: File is not valid UTF-8”Source must be UTF-8. The file holds bytes that are not, often from an editor that saved it in a legacy encoding.
Fix: save the file as UTF-8.
E0101: Tab in indentation
Section titled “E0101: Tab in indentation”Indentation is spaces only, so that every tool sees the same depth.
Fix: replace each tab at the start of a line with 4 spaces. lucid fix does this.
E0102: Indentation width is wrong
Section titled “E0102: Indentation width is wrong”Each block is exactly 4 spaces deeper than the line that opens it.
if true print "x"Fix: indent the block by 4 spaces more than its opening line.
E0103: Unexpected character
Section titled “E0103: Unexpected character”The character starts no token in Lucid.
let a = 1 $ 2Fix: remove the character, or put it inside text.
E0104: Text is not closed
Section titled “E0104: Text is not closed”A " starts text, and the line ends before the closing ".
print "abcFix: close the text on the same line, or use """ for text over many lines.
E0105: Unknown escape
Section titled “E0105: Unknown escape”Text knows only the escapes \n, \t, \r, \\, and \".
print "a\qb"Fix: write \\ for a backslash, or use one of the known escapes.
E0106: Single } in text
Section titled “E0106: Single } in text”{ and } in text mark interpolation, so a lone } is ambiguous.
print "a}b"Fix: write }} for a literal }, and {{ for a literal {. lucid fix writes }}.
E0107: Malformed number
Section titled “E0107: Malformed number”A number is digits, with _ only between digits, an optional fraction, and an optional exponent. A prefix such as 0x needs digits after it.
let a = 0xFix: complete the number, as in 0xff, or remove the stray part.
E0108: Text after an opening """
Section titled “E0108: Text after an opening """”Text over many lines starts on the line after """.
print """abc """Fix: end the line after the opening """, and start the text on the next line.
E0201: Unexpected token
Section titled “E0201: Unexpected token”The parser expected one kind of token and found another. The message says what it expected.
let = 1Fix: write what the message expects at that place.
A note names the usual cause in four places: a { in text that starts an interpolation, where {{ gives a literal brace; a match arm with no ->; a nested match written after -> on the same line, which needs its own indented block; and a , inside (), since there are no tuples.
E0202: Invalid assignment target
Section titled “E0202: Invalid assignment target”Only a name, a field, or an index can take a new value.
1 + 2 = 3Fix: assign to a name, as in let a = 1 + 2.
E0203: match used as a value has a block arm
Section titled “E0203: match used as a value has a block arm”A match that gives a value needs one expression in each arm.
let b = 1let a = match b _ -> print "x"Fix: make each arm one expression, or use a match statement that assigns to a var.
E0204: Chained comparison or range
Section titled “E0204: Chained comparison or range”a < b < c reads differently in different languages, so Lucid rejects it.
let a = 1 < 2 < 3Fix: join comparisons with and, as in 1 < 2 and 2 < 3.
E0205: Nesting over 128 levels, or over 1024 operators in one expression
Section titled “E0205: Nesting over 128 levels, or over 1024 operators in one expression”The compiler limits depth so that deep input cannot overflow its stack.
Fix: split the expression or the blocks into smaller tasks or named values.
E0206: Declaration only allowed at top level
Section titled “E0206: Declaration only allowed at top level”use, type, choice, trait, test, and extern tasks sit at top level only.
if true use std.fsFix: move the declaration to the top level of the file.
E0301: Name is not defined
Section titled “E0301: Name is not defined”No name in scope has this spelling. A note names a close match, if one exists.
let total = 1print totlFix: correct the spelling, or define the name before its use. If one name in sight is a close spelling, lucid fix renames to it.
E0302: Type is not defined
Section titled “E0302: Type is not defined”No type in scope has this name.
let a: Thing = 1Fix: correct the spelling, declare the type, or use the module that has it.
E0303: Types do not fit
Section titled “E0303: Types do not fit”A value has one type where another is needed. The message names both.
let a: int = "one"Fix: give a value of the needed type, or convert it, as in text.to_int() or int.to_text().
A call that gives no value, such as push, send, close, or update, used as a value is E0303 too, and so is .pop() or .receive() inside a larger expression. Make the call a statement, or the whole value of let, var, return, or an assignment. The test is channel_form.
E0304: Name is already defined in this scope
Section titled “E0304: Name is already defined in this scope”Two declarations in one scope use the same name.
let a = 1let a = 2Fix: rename one of them, or use var and assign the new value.
A type named like a built-in type or trait, such as Order or int, also gets this error. The message names the built-in it clashes with.
E0305: Name cannot change
Section titled “E0305: Name cannot change”The target of an assignment or change is a let, a parameter that is not change, or a slice.
let a = 1a = 2Fix: declare it with var, or mark the parameter change.
E0306: Task uses a top-level var
Section titled “E0306: Task uses a top-level var”A task sees top-level let values, but not var ones, so that every change shows in a signature.
var count = 0
task f() -> int return countFix: pass the value as a parameter, with change if the task changes it.
E0307: Arguments or parameters are in the wrong form
Section titled “E0307: Arguments or parameters are in the wrong form”A call has missing, extra, repeated, or misnamed arguments, or a parameter has no default after one that has one.
task f(a: int) -> int return a
print f()Fix: match the call to the parameters, by position or by name.
E0308: Called value is not a task
Section titled “E0308: Called value is not a task”Only a task or a task value can be called.
let a = 1print a(2)Fix: call a task, or remove the parentheses.
E0309: Task may end without returning
Section titled “E0309: Task may end without returning”A task with a result type must return on every path.
task f(a: bool) -> int if a return 1Fix: add a return at the end, or an else branch that returns.
E0310: return outside a task
Section titled “E0310: return outside a task”Top-level code is not a task, so it has nothing to return from.
returnFix: remove the return, or move the code into a task.
E0311: break or continue outside a loop
Section titled “E0311: break or continue outside a loop”These only work inside while or for, in the same task.
breakFix: remove it, or move it into a loop.
E0312: Number does not fit its type
Section titled “E0312: Number does not fit its type”A literal is outside the range of its type.
let a = 9223372036854775808Fix: use a smaller number, or a type with a larger range, such as u64 or float.
E0313: Default is not a literal
Section titled “E0313: Default is not a literal”A parameter or field default must be a literal value, or an empty [] or {}, so that a signature tells everything.
task f(a: int = 1 + 1) returnFix: write the value as one literal, as in a: int = 2.
E0314: Empty list or map has no type to take
Section titled “E0314: Empty list or map has no type to take”[] and {} need a type from an annotation or from where they go.
let a = []Fix: annotate it, as in let a: list[int] = [].
E0315: Alias is defined by itself, or a type holds itself with no way to end
Section titled “E0315: Alias is defined by itself, or a type holds itself with no way to end”A recursive type needs a variant or an optional field that ends it.
type Loop next: LoopFix: make the field optional, as in next: Loop?, or add a choice variant with no fields.
E0316: match does not cover every case
Section titled “E0316: match does not cover every case”Every variant or value must have an arm, so that adding a variant shows each place to update.
choice Light Red Green
let light = Redmatch light Red -> print "stop"Fix: add the missing arms, or a final _ arm.
E0317: match arm can never run
Section titled “E0317: match arm can never run”An earlier arm already covers everything this arm would.
let a = 1match a _ -> print "any" 1 -> print "one"Fix: remove the arm, or move it above the arm that covers it.
E0318: Pattern does not fit its value
Section titled “E0318: Pattern does not fit its value”The pattern names an unknown variant, has the wrong number of names, binds a type or variant name, holds {} in text, or names a type that the value never has.
choice Shape Circle(radius: float) Square(side: float)
let shape = Square(side: 1.0)match shape Circl(r) -> print r _ -> print "other"Fix: spell the variant as declared, with one name per field.
E0319: Type argument cannot be told from the values
Section titled “E0319: Type argument cannot be told from the values”A generic task must find each type parameter from its arguments, or be given it.
task make[T]() -> list[T] return []
let a = make()Fix: give the type in brackets, as in make[int]().
E0320: Type does not have a trait that a bound or operator needs
Section titled “E0320: Type does not have a trait that a bound or operator needs”An operator or a bound needs a trait, such as Equal for == and in, or Order for <.
task has[T](value: T, items: list[T]) -> bool return value in itemsFix: add the bound, as in [T: Equal], or use a type that has the trait.
E0321: Wrong number of type arguments
Section titled “E0321: Wrong number of type arguments”A generic name takes a fixed number of type arguments.
task plain(a: int) return
plain[int](1)Fix: give as many type arguments as the declaration has parameters.
E0322: Type form where a value belongs, or a value where a type belongs
Section titled “E0322: Type form where a value belongs, or a value where a type belongs”A type such as int? was used as a value, or a value was used in type brackets.
let a = 1print a?Fix: put a type only in an annotation or in brackets, and a value only in an expression.
E0323: Task named after a derived task or operator has the wrong form
Section titled “E0323: Task named after a derived task or operator has the wrong form”A hand-written show, equal, compare, or hash replaces a derived one, so it must have that task’s parameters and result.
type Point x: int
task show(self: Point) -> int return self.xFix: use the form of the derived task, here task show(self: Point) -> text, or pick another name.
E0324: Lambda or channel has no type to take from its context, or a lambda has try and no result type from it
Section titled “E0324: Lambda or channel has no type to take from its context, or a lambda has try and no result type from it”A lambda takes its parameter types from where it goes, such as a parameter of task type.
let double = n => n * 2Fix: annotate the name, as in let double: task(int) -> int = n => n * 2, or write a nested task.
channel(16) with no type and no context to take one from is E0324 too. Fix: write channel[int](16).
E0325: Lambda or nested task captures a name that can change
Section titled “E0325: Lambda or nested task captures a name that can change”A capture copies a value, so capturing a var would hide later changes.
var n = 1let add: task(int) -> int = m => m + nFix: copy the value into a let first, and capture that.
E0326: A value is used while something changes it
Section titled “E0326: A value is used while something changes it”Two change arguments overlap, a statement uses what it changes, a for body changes what it visits, or a value is read while a for change loop holds it.
task swap(change a: int, change b: int) let c = a a = b b = c
var x = 1swap(change x, change x)Fix: pass separate values, or copy one into a new name first.
E0327: try or else on a value with no error type or none to act on, or with nothing left after it
Section titled “E0327: try or else on a value with no error type or none to act on, or with nothing left after it”try and else act on a value whose type has an error or none in it.
let a = 1 else 2Fix: remove the try or else, since the value cannot fail.
E0328: An error that nothing uses
Section titled “E0328: An error that nothing uses”A result that may be an error must be handled, so a failure is never lost.
use std.fs
fs.write_text("out.txt", "hi")Fix: handle it with try, else, or a match.
E0329: A test name holds {}, or repeats
Section titled “E0329: A test name holds {}, or repeats”A test name is plain text, and new in its file, so that a report names one test.
test "adds" expect 1 + 1 == 2
test "adds" expect 2 + 2 == 4Fix: give each test its own name, with no {}.
E0330: A call to an extern task or .pointer() is outside an unsafe block
Section titled “E0330: A call to an extern task or .pointer() is outside an unsafe block”Foreign code can break every guarantee, so each use is marked.
unsafe extern task strlen(text: pointer[byte]) -> int
let bytes = "abc".bytes()print strlen(bytes.pointer())Fix: put the call in an unsafe block with a comment that says why it is safe.
E0331: An extern task has a form that C cannot take
Section titled “E0331: An extern task has a form that C cannot take”An extern task takes and gives only numbers, bool, and pointer[byte], sits at top level, is not used as a value, and has one form in the whole program. .pointer() works only on a list[byte] name.
unsafe extern task strlen(text: text) -> intFix: use a type that C can take, such as pointer[byte] from .pointer().
E0332: An unsafe block has no comment
Section titled “E0332: An unsafe block has no comment”The comment on the line before an unsafe block says why the code in it is safe.
unsafe extern task abs(n: i32) -> i32
unsafe print abs(-1)Fix: add a # comment on the line before unsafe.
E0333: A private name or task with self is used from another module
Section titled “E0333: A private name or task with self is used from another module”A module shares only what is marked public.
Fix: mark the declaration public, or use what the module already shares.
E0334: The file of a use does not exist, or is spelled with other letter case
Section titled “E0334: The file of a use does not exist, or is spelled with other letter case”A use ./a.b reads a/b.lcd from the directory of the file. Letter case must match the disk, so the program works on every system.
Fix: correct the path, or match the letter case of the file on disk.
E0335: Modules import each other in a cycle
Section titled “E0335: Modules import each other in a cycle”Imports must form a tree, so a module can load with no partial state.
Fix: move what both modules need into a third module that both import.
E0336: An imported module holds something other than declarations and literal let values
Section titled “E0336: An imported module holds something other than declarations and literal let values”Only the entry file runs code, so importing a module never has an effect.
Fix: move the statements to the entry file, or into a task.
E0337: A use with no ./ names something that is not a dependency of the file’s package
Section titled “E0337: A use with no ./ names something that is not a dependency of the file’s package”use name means std or a dependency in the package’s own lucid.toml.
Fix: add the dependency to lucid.toml, or write ./ for a local file.
E0338: lucid.toml is not valid
Section titled “E0338: lucid.toml is not valid”The manifest has bad syntax, a form outside the supported TOML, an unknown key, a bad name or version, or a files or env item that is empty or holds a control character, such as the line break that "\n" makes.
Fix: correct the line the message names. A manifest holds [package] with name and version, and [dependencies].
E0339: A package has no entry file or two, or a dependency is wrong
Section titled “E0339: A package has no entry file or two, or a dependency is wrong”A package has src/main.lcd or src/lib.lcd, not both. A use ./ cannot reach a file under another lucid.toml, since that file would have the other package’s permissions. A dependency must exist, have the name it is given, be a library, and not share a name with another package. lucid run cannot run a library.
Fix: follow the message: add or remove an entry file, or correct the dependency’s path or name.
E0340: A package uses a permission it does not hold
Section titled “E0340: A package uses a permission it does not hold”A package’s use of a std module, its unsafe block or extern, or a dependency’s permissions go beyond what its lucid.toml grants. A dependency may hold only what its allow entry names, a package may only allow what it holds, and a dependency’s files and env lists must fall inside its parent’s. See “Package permissions” in docs/security.md.
For example, use std.fs in a package whose lucid.toml has no files permission. The tests are in tests/package/perm_*, since they need a manifest.
Fix: add the permission to [permissions] in the package’s lucid.toml, as files = ["./notes"], or to the allow entry of the dependency that needs it.
E0341: spawn is not given a call of a task, or is given a change argument
Section titled “E0341: spawn is not given a call of a task, or is given a change argument”spawn runs one call of a task on a new thread, by decision 171. A built-in task, such as .len(), is not a task call, and a change argument would let two threads hold one variable.
let job = spawn 1 + 2Fix: spawn a call of a task, as spawn add(1, 2). For a change argument, pass the value, and return the new one, which .wait() gives.
E0901: Parses, but cannot run at this milestone
Section titled “E0901: Parses, but cannot run at this milestone”The feature is in the language, but not built yet, or not built yet for lucid build --target web. lucid check does not report this code.
let a = [1, 2]let b = {1: 2}[0..1]Fix: see docs/roadmap.md for when it arrives, and use a built feature until then.
E0902: Task frame is too large for the stack check
Section titled “E0902: Task frame is too large for the stack check”A task’s frame is over 512 KiB, or over half the stack for top-level code. Only code generation finds this, so lucid check does not report it.
Fix: split the task into smaller tasks.
E0903: Too many generic instances
Section titled “E0903: Too many generic instances”Over 20,000 instances, or a type argument of over 256 parts, usually from a generic task that calls itself with a larger type.
task grow[T](value: T) -> int return grow([value])
print grow(1)Fix: call the task with the same type it was given, or remove the type growth.
E0904: No library has this foreign task
Section titled “E0904: No library has this foreign task”An extern task must be in the C runtime or kernel32.
unsafe extern task no_such_symbol_anywhere(x: int) -> intFix: correct the name, or use a task that one of those libraries has.
E0905: Foreign code cannot run on the web
Section titled “E0905: Foreign code cannot run on the web”A user extern task or .pointer() is in a program built with lucid build --target web. WebAssembly in a page reaches no C library, by decision 162. Only code generation for the web finds this, so lucid check and lucid run do not report it. The test is web_rejects_foreign_code.
Fix: build the program without --target web, or move the foreign code out of what the page uses.
E0906: std.dom works only in a browser
Section titled “E0906: std.dom works only in a browser”A program that uses std.dom ran with lucid run or lucid test, or was built without --target web. A page needs a browser, by decision 162. lucid check does not report this code.
use std.dom
print "page"Fix: build it with lucid build --target web, and open the page that loads the .js file.
E0907: spawn, std.net, or std.http cannot run on the web
Section titled “E0907: spawn, std.net, or std.http cannot run on the web”A program built with lucid build --target web uses spawn, use std.net, or use std.http. Threads in WebAssembly need shared memory, which browsers allow only on pages with cross-origin isolation headers, and a page cannot open a socket, by decision 176. Only a build for the web finds this, so lucid check and lucid run do not report it. The test is web_rejects_spawn.
Fix: build the program without --target web, or do the work in one thread. A page talks to a server with the browser’s own requests.