Diagnostics
Elci reports each error with a stable code and a source location, shows the source code it is about and suggests a fix. This page explains how to read a diagnostic, how a run reports several errors, and how tools can read them. It then lists every code, and shows the most common errors with a small program that triggers each one, the exact output and the fix.
Reading a diagnostic
Section titled “Reading a diagnostic”A compile error starts with one line, path:line:column: code: message. A blank line follows, then the
source line with carets under what the error is about, then any hints:
src/Main.elm:6:5: ELCI2005: Unknown name 'lenght'
6| lenght [ 1, 2 ] ^^^^^^Hint: did you mean `List.length`?
For more on ELCI2005, run `elci explain ELCI2005`.- The first line has the same form for every error, so editors and scripts can parse it. The
path is the file of the module where the problem is, which may be a module imported by the one you
compiled. A problem inside a bundled module such as
Listis reported where your code uses it, or otherwise as<bundled>/List.elm. - The code names the class of error and never changes between releases. The message says what is
wrong in terms of your code: which argument, branch, list element, operator side, annotation or field
has the wrong type, or which patterns a
casedoesn’t cover. - The excerpt shows the line with its number, and underlines what the error is about. For an error at the end of the file, it points just past the last code. An error in a bundled module has no excerpt.
- Each hint suggests a likely fix: a close name, a conversion such as
String.fromInt, or an import to add. An error has zero or more hints. - The last line names the codes of the run and the command that explains them; see
elci explain. The examples in the rest of this page leave it out and show only the diagnostic. Some show only its first line, without the excerpt and hints.
Types in messages are written as in source, in backticks: Result a Int, Order. When two types of one
name meet in a message, both are qualified, as in Main.Value and Julc.Ledger.Value.
For a validator, the elci.toml table follows the diagnostic, on its own line:
my-project/src/Main.elm:6:1: ELCI2013: Functions cannot be serialized as datum or redeemer
6| mint : (Int -> Int) -> ScriptContext -> Bool ^^^^
In my-project/elci.toml:6: [validators.main]Every error makes the command exit with status 1. Codes starting with ELCI1 come from the lexer and
parser, ELCI20 from type checking, ELCI21 from modules and imports, ELCI3 from code generation and
ELCI4 from configuration and the backend.
What is underlined
Section titled “What is underlined”The carets underline the reported token, such as a name, a qualified name or a string literal with its
quotes. When the error is about a whole expression, they underline all of it. This is the case for an
argument, a list element, the body of a case branch and a field access such as .price:
main : Stringmain = String.fromInt (String.append "4" "2")src/Main.elm:6:20: ELCI2002: The 1st argument to `String.fromInt` is `String`, but `String.fromInt` needs `Int`
6| String.fromInt (String.append "4" "2") ^^^^^^^^^^^^^^^^^^^^^^^An expression over several lines is underlined on each of its lines, up to five:
main : Stringmain = String.fromInt (String.append "4" "2" )src/Main.elm:7:9: ELCI2002: The 1st argument to `String.fromInt` is `String`, but `String.fromInt` needs `Int`
7| (String.append ^^^^^^^^^^^^^^ 8| "4" ^^^ 9| "2" ^^^10| ) ^The line and column of the first line are where the underline starts. A longer expression shows its
first five lines, then a line with ….
Some expressions are reported at a token inside them: an operation such as "x" ++ "y" at its operator,
and a call without parentheses such as String.fromInt 3 at its last argument. The caret then marks that
token alone, as an underline from there would cover only part of the expression.
Long types
Section titled “Long types”When the two types of a mismatch are long, It is: and It needs: lines follow the excerpt. They show
the types one above the other, with the first difference marked:
type alias Order = { owner : String, amount : Int, deadline : Int }
amountOf : Order -> IntamountOf order = order.amount
main : Intmain = amountOf { owner = "alice", amount = "10", deadline = 5 }src/Main.elm:15:14: ELCI2002: The 1st argument to `amountOf` is `{ amount : String, deadline : Int, owner : String }`, but `amountOf` needs `{ amount : Int, deadline : Int, owner : String }`
15| amountOf { owner = "alice", amount = "10", deadline = 5 } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is: { amount : String, deadline : Int, owner : String }It needs: { amount : Int, deadline : Int, owner : String } ^^^The message still names both types, so the first line reads the same as for short types. The lines are added when the two types together are 60 characters or longer.
Colour
Section titled “Colour”On a terminal, the path and code, the carets and Hint: are in colour. Output to a file or a pipe is
plain, and so is any output when the NO_COLOR environment variable is set. --color overrides this on
any command:
| Option | Colour |
|---|---|
--color=auto | On a terminal, unless NO_COLOR is set. The default. |
--color=always | Always, also in a pipe. |
--color=never | Never. |
The text is the same, character for character, with and without colour. The JSON report is never coloured.
Several errors in one run
Section titled “Several errors in one run”A run reports every error it finds, not just the first. Compilation has three phases: lexing and parsing, name resolution, and type checking. Each phase reports all of its errors. A later phase runs only when the earlier ones found none, as in Elm, so one mistake isn’t reported again as a different error later.
fee : Intfee = "2"
total : Int -> Inttotal amount = amount + lenght [ 1 ]
label : Int -> Stringlabel amount = String.fromInt "amount"
main : Intmain = total feesrc/Main.elm:4:1: ELCI2002: The annotation of `fee` says it is `Int`, but its definition is `String`
4| fee : Int ^^^
src/Main.elm:11:14: ELCI2005: Unknown name 'lenght'
11| amount + lenght [ 1 ] ^^^^^^Hint: did you mean `List.length`?
src/Main.elm:16:20: ELCI2002: The 1st argument to `String.fromInt` is `String`, but `String.fromInt` needs `Int`
16| String.fromInt "amount" ^^^^^^^^
3 errors
For more on ELCI2002 and ELCI2005, run `elci explain <code>`.- Order. Errors are shown in source order: by module, then by line and column. A blank line separates them.
- Count. When there is more than one error, a line such as
3 errorsfollows them. - Limit. A run shows at most 20 errors, then a line such as
... and 3 more. The count still gives the total. - One per declaration. Each top-level declaration reports its first error. A declaration whose
definition fails still has the type its annotation gives it, so its callers are checked against the
annotation and don’t report errors of their own. Above,
mainpassesfeetototal, which needs anInt. The annotation saysfeeis one, somainis not reported. - Once each. A mistake that fails several checks alike, such as each comparison inside
List.sort, is reported once. - Phases. A module with a syntax error is not type-checked. Nor is a program with an import or
qualified-name error (
ELCI21xx), such asLsit.length. Fix those, and the next run reports the type errors. An unknown unqualified name (ELCI2005), as above, is found while type checking and is reported with the type errors. - One at a time. Code generation (
ELCI3xxx), configuration and command-line errors (ELCI4xxx) still stop the run at the first error.
elci explain
Section titled “elci explain”A failed run’s text report ends with a line that names its codes and how to read more about them:
For more on ELCI2005, run `elci explain ELCI2005`.For more on ELCI2002 and ELCI2005, run `elci explain <code>`.elci explain prints the entry for a code: what it means and its common causes, a failing example with
its exact output, the fix, and where to read more. ELCI2005, elci2005 and 2005 all name the same
code:
$ elci explain 2005ELCI2005: Unknown name
A value name is used that nothing in scope defines.
Common causes:
- A misspelling. The hint suggests up to three close names, local ones first.- A name from another module that is not imported, or that its import doesn't expose. The hint says how to reach it, such as writing `Helper.double`.- A name a Java library module doesn't export.
A qualified name such as `List.lenght` is ELCI2104.
Example
main : Int main = lenght [ 1, 2 ]
`elci check` reports:
src/Main.elm:6:5: ELCI2005: Unknown name 'lenght'
6| lenght [ 1, 2 ] ^^^^^^ Hint: did you mean `List.length`?
Fix
Correct the spelling, or import the module that defines the name:
main : Int main = List.length [ 1, 2 ]
See also
- The Diagnostics reference, section ELCI2005.- ELCI2104, for qualified names.elci explain without a code lists every code with its title. The entries are part of the compiler and
match its version. Each entry’s example is tested to give exactly the output it shows, and its fix to
compile. An unknown code is an ELCI4001 error.
JSON reports for tools
Section titled “JSON reports for tools”elci check, elci build, elci eval and elci test take --report=json. Each error is then printed on
standard error as one JSON object on its own line (JSON Lines). A run with one
error prints one line:
$ elci check --report=json{"code":"ELCI2005","path":"src/Main.elm","line":6,"column":5,"message":"Unknown name 'lenght'","hints":["did you mean `List.length`?"],"excerpt":"6| lenght [ 1, 2 ]\n ^^^^^^","context":null}A run with several errors prints one line for each, in the same order and up to the same limit as the text report. Read the output line by line, and parse each line as JSON:
$ elci check --report=json{"code":"ELCI2002","path":"src/Main.elm","line":4,"column":1,"message":"The annotation of `fee` says it is `Int`, but its definition is `String`","hints":[],"excerpt":"4| fee : Int\n ^^^","context":null}{"code":"ELCI2005","path":"src/Main.elm","line":11,"column":14,"message":"Unknown name 'lenght'","hints":["did you mean `List.length`?"],"excerpt":"11| amount + lenght [ 1 ]\n ^^^^^^","context":null}{"code":"ELCI2002","path":"src/Main.elm","line":16,"column":20,"message":"The 1st argument to `String.fromInt` is `String`, but `String.fromInt` needs `Int`","hints":[],"excerpt":"16| String.fromInt \"amount\"\n ^^^^^^^^","context":null}The JSON report has no count line, no ... and N more line and no elci explain line.
| Field | Type | Contents |
|---|---|---|
code | string or null | The ELCI code; null for a failure that has no code |
path | string or null | The file, as on the first line of the text report |
line, column | number or null | The position, counting from 1 |
message | string | The message, without the path and code |
hints | array of strings | The hints, without Hint:; empty when there are none |
excerpt | string or null | The source lines and their caret lines, separated by \n; null when there is no source to show |
context | string or null | For a failure in a named validator, its elci.toml line and table; otherwise null |
The It is: and It needs: lines of a long mismatch are not part of the JSON; the message names both
types. A failure in a validator names its table in context:
{"code":"ELCI2013","path":"my-project/src/Main.elm","line":6,"column":1,"message":"Functions cannot be serialized as datum or redeemer","hints":[],"excerpt":"6| mint : (Int -> Int) -> ScriptContext -> Bool\n ^^^^","context":"my-project/elci.toml:6: [validators.main]"}A failure without a source location keeps the same fields, with null location fields:
{"code":"ELCI4001","path":null,"line":null,"column":null,"message":"unknown validator 'treasury'; configured: main","hints":[],"excerpt":null,"context":null}The exit status is the same with or without the option. Results stay text on standard output: the lines of
elci check and elci build, the value and budget of elci eval or its evaluation failed: line, and
test results, including failing tests. The other commands reject the option with ELCI4001.
All codes
Section titled “All codes”| Code | Meaning |
|---|---|
ELCI1001 | Invalid source character or literal |
ELCI1002 | Malformed or unsupported syntax |
ELCI2001 | Invalid pattern or expression form |
ELCI2002 | Type mismatch, or a type that would have to contain itself |
ELCI2003 | Unsupported equality, ordering or append type; a constrained type variable that is missing or misnamed; a Dict decoded from Data whose keys aren’t comparable |
ELCI2004 | Missing required top-level signature |
ELCI2005 | Unknown value name |
ELCI2006 | Duplicate binder or unreachable pattern |
ELCI2007 | Non-exhaustive case expression |
ELCI2008 | Eager recursive value cycle |
ELCI2009 | Non-concrete handler, entrypoint or property |
ELCI2010 | Unknown or unconstrained record field |
ELCI2011 | Duplicate type or constructor, or a built-in constructor or type name (Just, Nothing, True, False; Int, Maybe, List and the other built-in types) |
ELCI2012 | Invalid type, alias, arity or alias cycle; Tuple or Unit written as a type name |
ELCI2013 | Unsupported serialized boundary type, such as a Value in a datum, or a value without a Data encoding (a function or an Array) stored in data |
ELCI2014 | Validator handler signature does not match its purpose, parameters or datum profile |
ELCI2101 | Unknown or missing module or imported export; a source module importing the test library |
ELCI2102 | Ambiguous name: two imports expose different things under it |
ELCI2103 | Entrypoint or handler is not exposed |
ELCI2104 | Module path, ownership or cycle error; a reserved module name or alias; a name a module lacks, an Elm function Elci doesn’t have, or a module used without its import |
ELCI2105 | Unsupported Java export signature, with the provider’s reason; a Java export whose result can hold a Value |
ELCI3001 | The inferred program cannot be lowered, such as Julc.Data.decode or a Java library generic at a type nothing determines |
ELCI3002 | Specialization limit or polymorphic recursion |
ELCI3003 | A generic library type argument or a Data conversion needs a Data encoding; a Java library generic used at a type containing a Dict or a Value |
ELCI4001 | Invalid project configuration or command-line request, including a [java-modules] key that names a core module and an elci apply parameter that doesn’t fit its type |
ELCI4002 | Julc’s backend rejected the generated code |
ELCI4003 | The Julc backend lacks a capability the program needs |
Syntax errors
Section titled “Syntax errors”ELCI1001: invalid character or literal
Section titled “ELCI1001: invalid character or literal”main : Intmain = 1.5src/Main.elm:6:6: ELCI1001: Float is unsupported; represent fractional amounts using an explicit integer scale
6| 1.5 ^Fix: use integers with an explicit scale, such as lovelace instead of ada or basis points instead of
percentages. The same code reports tabs, unsupported characters such as % or ' and unknown string
escapes.
ELCI1002: malformed or unsupported syntax
Section titled “ELCI1002: malformed or unsupported syntax”The message says what is wrong. Refutable patterns in function arguments are a common case:
first : List Int -> Intfirst (x :: _) = xsrc/Main.elm:5:8: ELCI1002: Function parameters require irrefutable patterns; use case for refutable matching
5| first (x :: _) = ^Fix: match with case, and handle every shape:
first : List Int -> Intfirst values = case values of x :: _ -> x
[] -> 0Other ELCI1002 messages include Comparison operators cannot be chained; use && or explicit parentheses (for 1 < 2 < 3), Mixing (<|) and (|>) needs parentheses: they associate in opposite directions, as in Elm (for f <| x |> g), Extensible records are unsupported; use a closed record and
Tuples have two or three elements.
ELCI2001: invalid expression or pattern
Section titled “ELCI2001: invalid expression or pattern”main : Intmain = 7 / 2src/Main.elm:6:7: ELCI2001: Float division is unsupported; use // for integer quotient
6| 7 / 2 ^Fix: 7 // 2, together with modBy or remainderBy when you need the rest. The function (/) is
rejected the same way, with a suggestion to use (//).
ELCI2001 also covers patterns that can’t match their value’s shape. A constructor pattern must give the
constructor all of its arguments:
main : Intmain = case Just 1 of Just x y -> x
Nothing -> 0src/Main.elm:7:9: ELCI2001: The constructor Just takes 1 argument, but this pattern gives it 2
7| Just x y -> ^^^^A misspelt constructor in a pattern gets a suggestion:
src/Main.elm:7:9: ELCI2001: Unknown constructor Jsut in this pattern
7| Jsut n -> ^^^^Hint: did you mean `Just`?A record pattern such as { index } can’t take apart a ledger record. Read its fields instead:
src/Main.elm:10:9: ELCI2001: TxOutRef is a library record, which a pattern cannot take apart; read its fields with `.index` insteadType errors
Section titled “Type errors”ELCI2002: type mismatch
Section titled “ELCI2002: type mismatch”main : Stringmain = String.fromInt "42"src/Main.elm:6:20: ELCI2002: The 1st argument to `String.fromInt` is `String`, but `String.fromInt` needs `Int`
6| String.fromInt "42" ^^^^The message names the part of the code whose type differs, and the type it needs:
| Where | Example message |
|---|---|
| An argument | The 1st argument to `String.fromInt` is `String`, but `String.fromInt` needs `Int` |
A value piped in with |> | The 1st argument to `double`, the value piped in, is `String`, but `double` needs `Int` |
| Too many arguments | `max` takes 2 arguments, but it is given 3 |
| A value applied like a function | `fee` is `Int`, not a function, so it cannot take an argument |
The condition of an if | The condition of this if is `Int`, but it must be `Bool` |
The branches of an if | The branches of this if have different types: the then branch is `Int`, but the else branch is `String` |
A branch of a case | The 2nd branch of this case is `String`, but the first branch is `Int` |
| A pattern | This pattern matches `Maybe a`, but the value it is matched against is `Int` |
| A list element | The 3rd element of this list is `String`, but the elements before it are `Int` |
| An operator | The left side of :: is `String`, but the list on the right holds `Int`, The two sides of ++ have different types: the left is `String`, but the right is `Int` |
| A composition | The left side of >> returns `String`, but the right side takes `Int` |
| An annotation | The annotation of `add` says it returns `Int`, but its body is `String`, The annotation of `add` gives it 1 argument, but its definition has 2 parameters |
| A record field | The field `owner` is `String`, but it is used here as `Int` |
A too-many-arguments error also hints that a missing comma or parentheses can make values look like extra arguments.
A signature that claims more than the body delivers is also a mismatch:
identity : a -> aidentity value = value + 1src/Main.elm:4:1: ELCI2002: The annotation of `identity` says `a` can be any type, but its definition needs `Int`
4| identity : a -> a ^^^^^^^^Hint: write `Int` in the annotation, or make the definition work for any typeFix: make the signature match the body (increment : Int -> Int), or the body match the signature. An
annotation with two type variables that the definition needs to be the same says
The annotation of `pick` says `a` and `b` can be different types, but its definition needs them to be the same.
The annotations of mutually recursive functions are all read before any body is checked, so a mistake is
reported in the body that makes it.
Arithmetic operators name the types they accept, and suggest the right operator where there is one:
src/Main.elm:6:7: ELCI2002: The operator + works on Int values, not String; use ++ to appendComparisons on a type that has no order are ELCI2003, below.
Hints. A mismatch between types that are often confused carries a hint with the conversion:
main : Intmain = List.head [ 1, 2 ] + 1src/Main.elm:6:24: ELCI2002: The operator + works on Int values, not Maybe Int
6| List.head [ 1, 2 ] + 1 ^Hint: this is a Maybe: handle `Nothing` with a case, or use `Maybe.withDefault`The hints cover Int and String (String.fromInt), String and Bytes (Bytes.fromString,
Bytes.toString), Bytes and a ledger hash such as PubKeyHash (the constructor, or the .hash field),
a Maybe or Result and a plain value (a case, Maybe.withDefault, Result.withDefault or Just),
Value and Int (Value.lovelaceOf, Value.lovelace), Data and a typed value (Data.decode,
Data.encode), and a function where a value is needed (a missing argument). An error shows at most two
hints, and only those that fit the types. A pattern of the wrong type gets no hint.
A type that would have to contain itself, as when a generic function calls itself with a tuple of its
argument, is reported as
ELCI2002: This needs a type that contains itself: `a` would have to be `( a, a )`.
ELCI2003: unsupported equality, ordering or append
Section titled “ELCI2003: unsupported equality, ordering or append”double : Int -> Intdouble x = x * 2
main : Boolmain = double == doublesrc/Main.elm:11:12: ELCI2003: The operator == cannot compare Int -> Int values: functions have no equality
11| double == double ^^Equality is rejected for functions, Map, Array and imported types without approved equality, such as
TxOut. A Dict has equality when its values do, and a Value and Data always have it. When the
offending type is inside another, the message names it:
The operator == cannot compare List (Int -> Int) values: Int -> Int is part of them, and functions have no equality. ++ needs a String or a List: 1 ++ 2 gives
ELCI2003: The operator ++ appends String or List values, not Int.
Fix: compare the values you care about, such as a map’s lookups or a decoded datum, or keep keyed data
in a Dict, which has equality.
Ordering (<, compare, max, List.sort and the rest) needs a
comparable type. The message names the operation and the part
of the type that isn’t comparable:
main : Boolmain = ( 1, True ) < ( 2, False )src/Main.elm:6:17: ELCI2003: The operator < needs comparable values, but Bool, in ( Int, Bool ), is not comparable. Comparable types are Int, String, Bytes, byte-string ledger types such as PubKeyHash, and lists and tuples of comparable types
6| ( 1, True ) < ( 2, False ) ^For records and custom types, the message goes on to suggest a key:
src/Main.elm:10:5: ELCI2003: `List.sort` needs comparable values, but { age : Int, name : String } is not comparable. Comparable types are Int, String, Bytes, byte-string ledger types such as PubKeyHash, and lists and tuples of comparable types. Compare a comparable field instead, or sort with List.sortBy or List.sortWithFix: compare a comparable field, or sort with List.sortBy (\person -> person.age) or
List.sortWith.
A signature whose type variable is compared or appended must say so with its name, as in Elm (constrained type variables):
larger : a -> a -> alarger x y = if x > y then x
else ysrc/Main.elm:6:10: ELCI2003: The operator > compares values of type `a`, but the annotation of `larger` says `a` can be any type. Rename it `comparable` (as in Elm) to require comparable values
6| if x > y then ^Fix: write larger : comparable -> comparable -> comparable. For ++, the message suggests
appendable. A caller that then passes the wrong type is reported at the call:
ELCI2003: `twice` appends String or List values, not Int. Elm’s number has its own message:
src/Main.elm:4:1: ELCI2003: The annotation of `total` uses `number`, Elm's type variable for Int or Float. Elci has one number type: write IntDecoding a Dict checks that its keys are in order, so a Dict in a datum, a redeemer, a parameter or a
Julc.Data.decode result needs comparable keys:
src/Main.elm:9:5: ELCI2003: A Dict decoded from Data needs comparable keys, to check that they are in order; Bool is not comparable. Use a Map insteadFix: use a Map, whose keys may be any type with a Data encoding.
ELCI2004: missing signature
Section titled “ELCI2004: missing signature”double x = x * 2src/Main.elm:4:1: ELCI2004: Top-level declarations require a type signature
4| double x = ^^^^^^Fix: add double : Int -> Int directly above the definition. Local definitions do not need one.
ELCI2005: unknown name
Section titled “ELCI2005: unknown name”main : Intmain = lenght [ 1, 2 ]src/Main.elm:6:5: ELCI2005: Unknown name 'lenght'
6| lenght [ 1, 2 ] ^^^^^^Hint: did you mean `List.length`?Fix: correct the spelling, or import the module that defines the name. The hint lists up to three close names. It looks first at the names the module can write unqualified, local ones included, and then at qualified names. A name is close when it differs only in case, by one edit for a name of three to five characters, or by two edits for a longer name. Swapping two neighbouring letters counts as one edit.
A name that an imported module exposes, but that its import doesn’t list, gets a hint that says how to
reach it. Here the module Helper exposes double:
module Main exposing (main)
import Helper
main : Intmain = double 4src/Main.elm:8:5: ELCI2005: Unknown name 'double'
8| double 4 ^^^^^^Hint: write `Helper.double`, or expose `double` in its importA name that a Java library module doesn’t export is reported with a reminder to check its exports:
src/Main.elm:8:5: ELCI2005: Unknown name 'Math.maximum'; check that the imported module exports itA qualified name whose module is missing, not imported or lacks the name is ELCI2104; see
module and import errors.
ELCI2006: duplicate binder or unreachable pattern
Section titled “ELCI2006: duplicate binder or unreachable pattern”describe : Maybe Int -> Intdescribe value = case value of Just n -> n
Nothing -> 0
Just _ -> 1src/Main.elm:13:9: ELCI2006: Unreachable pattern
13| Just _ -> ^^^^Fix: remove the branch that can never match. A pattern that binds the same name twice, such as
( x, x ), gives ELCI2006: Duplicate pattern variable x.
ELCI2007: non-exhaustive case
Section titled “ELCI2007: non-exhaustive case”type Action = Buy Int | Sell Int | Cancel
amount : Action -> Intamount action = case action of Buy value -> value
Sell value -> valuesrc/Main.elm:12:5: ELCI2007: This case does not cover every possibility; it is missing `Cancel`
12| case action of ^^^^Hint: add a branch for each missing patternFix: add a Cancel -> branch. Prefer naming every constructor over _ ->, so that adding a
constructor later points you to every case to update.
The message lists the missing patterns as you would write them, including nested ones:
describe : Maybe (Result String Int) -> Stringdescribe value = case value of Just (Ok n) -> String.fromInt nsrc/Main.elm:6:5: ELCI2007: This case does not cover every possibility; it is missing `Nothing` and `Just (Err _)`
6| case value of ^^^^Hint: add a branch for each missing patternThe list is complete: a branch for each pattern in it makes the case exhaustive. It shows up to three
patterns, then how many more there are, as in
it is missing `Square _`, `Triangle _ _ _`, `Line` and 1 more. Lists and literals are covered too:
a case on a list with branches for [] and [ _ ] is missing _ :: _ :: _, and one on an Int or a
String without a _ branch is missing _.
ELCI2008: eager value cycle
Section titled “ELCI2008: eager value cycle”main : Intmain = let a = b + 1
b = a + 1 in asrc/Main.elm:7:9: ELCI2008: Cyclic eager values are unsupported; recursion requires functions
7| a = ^Fix: values are computed eagerly, so they cannot depend on each other in a loop. Break the cycle, or turn the recursion into a function.
ELCI2009: type is not concrete
Section titled “ELCI2009: type is not concrete”main : List amain = []src/Main.elm:4:1: ELCI2009: Entrypoints require concrete types
4| main : List a ^^^^A validator handler gets Handler Main.mint requires a concrete type, and a property test with generic
arguments gets a similar message. Fix: replace the type variable with a concrete type, such as
List Int.
ELCI2010: unknown record field
Section titled “ELCI2010: unknown record field”main : Intmain = let order = { amount = 5 } in order.pricesrc/Main.elm:10:10: ELCI2010: Missing field 'price'; available fields: [amount]
10| order.price ^^^^^^Fix: use one of the listed fields. A field name close to one of them, such as order.amont, also
gets the hint did you mean `amount`?. When Elci cannot tell which record a field access belongs to,
add a signature with the record type.
ELCI2011 and ELCI2012: invalid type declarations
Section titled “ELCI2011 and ELCI2012: invalid type declarations”Two custom types in one module cannot share a constructor name. No module may declare the built-in
constructors Just, Nothing, True or False, or a type named Int, Bool, String, Bytes,
Data, List, Maybe, Map, Array or Float:
src/Main.elm:9:6: ELCI2011: Duplicate constructor Buy: the type Action has one toosrc/Main.elm:4:6: ELCI2011: Nothing is a constructor of the built-in Maybe type; choose another namesrc/Main.elm:4:6: ELCI2011: Bytes is a built-in type; choose another nameA type applied to the wrong number of arguments, and type aliases that refer to each other in a loop,
are ELCI2012:
src/Main.elm:4:1: ELCI2012: The type List takes 1 argument, but it is given 2src/Main.elm:4:12: ELCI2012: Cyclic type alias: A -> B -> ATuple and unit types have their own syntax. Tuple Int Int and Unit are ELCI2012:
src/Main.elm:4:8: ELCI2012: Write tuple types as ( a, b ) or ( a, b, c )src/Main.elm:4:10: ELCI2012: Write the unit type as ()An unknown type name in a signature is also ELCI2012, reported at the declaration. A close type name is
suggested:
main : Strinmain = "x"src/Main.elm:4:1: ELCI2012: Type is not declared or imported in this module: Strin
4| main : Strin ^^^^Hint: did you mean `String`?Fix: declare or import the type, or correct its spelling.
Validator errors
Section titled “Validator errors”ELCI2013: type cannot cross the boundary
Section titled “ELCI2013: type cannot cross the boundary”A datum, redeemer or parameter must have a strict Data encoding:
mint : (Int -> Int) -> ScriptContext -> Boolmint _ _ = Truemy-project/src/Main.elm:6:1: ELCI2013: Functions cannot be serialized as datum or redeemer
6| mint : (Int -> Int) -> ScriptContext -> Bool ^^^^
In my-project/elci.toml:6: [validators.main]A Value is rejected the same way:
my-project/src/Main.elm:7:1: ELCI2013: A Value cannot be part of a datum, redeemer or parameter yet: the ledger's strict boundary cannot check its form. Store a List ( PolicyId, TokenName, Int ) and rebuild it with Value.fromList
7| mint : Value -> ScriptContext -> Bool ^^^^
In my-project/elci.toml:6: [validators.main]So is a ledger type that contains one, such as TxOut:
ELCI2013: TxOut has no approved strict Data boundary (BOUNDARY); for example records containing a ledger Value (such as TxOut) cannot be checked.
Fix: use your own record or custom type, or a ledger type with an approved boundary such as TxOutRef
or PubKeyHash. For an amount of tokens, store a List ( PolicyId, TokenName, Int ) and rebuild the value
with Value.fromList.
The same code rejects an Array stored anywhere in data (a record, list or tuple field, or a datum,
redeemer or parameter), in any project:
module Main exposing (main)
import Array exposing (Array)
type alias Book = { pages : Array Int }
main : Intmain = let books = [ { pages = Array.fromList [ 1 ] } ] in List.length bookssrc/Main.elm:10:1: ELCI2013: Arrays have no Data encoding and cannot be stored in data; keep a List and convert it with Array.fromList
10| main : Int ^^^^ELCI2014: handler signature does not match
Section titled “ELCI2014: handler signature does not match”A spend handler with only a redeemer and context:
spend : () -> ScriptContext -> Boolspend _ _ = Truemy-project/src/Main.elm:6:1: ELCI2014: Handler Main.spend does not have the spend signature datum -> redeemer -> ScriptContext -> Bool that [validators.main] needs (0 parameters); its type is () -> ScriptContext -> Bool; it has `Bool` where the configuration needs `ScriptContext -> Bool`
6| spend : () -> ScriptContext -> Bool ^^^^^
In my-project/elci.toml:6: [validators.main]The message gives the signature the table needs, how many parameters it declares and the handler’s
actual type. The part in parentheses names the first pair of types that differ. The same code reports a missing parameter argument (does not have the mint signature owner -> redeemer -> ScriptContext -> Bool that [validators.main] needs (1 parameter)) and a datum that
should be a Maybe (uses spend-datum = "optional", so its datum must have type Maybe d, not Int). Fix: make the signature match the table in
elci.toml: parameters first, then the datum (for spend), the redeemer
and the ScriptContext.
ELCI2103: not exposed
Section titled “ELCI2103: not exposed”my-project/src/Main.elm:11:1: ELCI2103: Handler Main.mint must be exposed by its module
11| mint : () -> ScriptContext -> Bool ^^^^
In my-project/elci.toml:6: [validators.main]An [entrypoint] function that its module doesn’t expose gets
ELCI2103: Entrypoint Main.main must be exposed by its module.
Fix: add the handler, or the [entrypoint] function, to the module’s exposing list.
Module and import errors
Section titled “Module and import errors”ELCI2101, ELCI2102 and ELCI2104
Section titled “ELCI2101, ELCI2102 and ELCI2104”A module that is neither a source file nor a [java-modules] mapping, or an unknown ledger type, is
ELCI2101, reported at the import:
import Julc.Nope as Nopesrc/Main.elm:3:1: ELCI2101: Missing source module: Julc.Nope; add Julc/Nope.elm under a source directory, or map a Java library to it under [java-modules]
3| import Julc.Nope as Nope ^^^^^^import Julc.Ledger exposing (Hash)src/Main.elm:3:1: ELCI2101: Unknown ledger record type Hash
3| import Julc.Ledger exposing (Hash) ^^^^^^A misspelt module, ledger type or exposed name in an import gets a suggestion:
src/Main.elm:3:1: ELCI2101: Unknown ledger type Credentail
3| import Julc.Ledger exposing (Credentail(..)) ^^^^^^Hint: did you mean `Credential`?The test library (Expect, Scenario, Property) is only for test modules. A source module that imports
it is rejected. elci test reports:
src/Main.elm:3:1: ELCI2101: Only test modules can import Expect; it is part of the test library, not available to elci buildelci check and elci build report it when a validator reaches that module:
src/Main.elm:3:1: ELCI2101: Expect is part of the test library; only test modules can import itImports of existing modules fail with ELCI2104 when the name is not exposed:
import Map exposing (lookup)src/Main.elm:3:1: ELCI2104: Map does not expose 'lookup'
3| import Map exposing (lookup) ^^^^^^A qualified name gives one of three messages, depending on the module. The hint suggests close names:
| Situation | Message |
|---|---|
| The module is imported, but doesn’t expose the name | Module Helper does not expose 'doubel' |
| A project or Java module exists, but this module doesn’t import it | Module Helper is not imported; add `import Helper` |
| No imported module has that name | No module Lsit is imported, and none has that name |
main : Intmain = Lsit.length [ 1, 2 ]src/Main.elm:6:5: ELCI2104: No module Lsit is imported, and none has that name
6| Lsit.length [ 1, 2 ] ^^^^^^^^^^^Hint: did you mean `List.length`?A qualified name must use the name the module is imported under. After import Shop.Pricing without
as Pricing, Pricing.priceOf gets the third message; write Shop.Pricing.priceOf.
A qualified name that a core module lacks lists what the module has. For Elm functions that Elci doesn’t provide, the message says what to use instead:
src/Main.elm:8:5: ELCI2104: Elci's Map module has no lookup. It has empty, filter, foldl, foldr, fromList, get, insert, isEmpty, keys, map, member, remove, singleton, size, toList, update, valuessrc/Main.elm:6:5: ELCI2104: Elci has no Debug.log; use Debug.trace message value, which returns valuesrc/Main.elm:6:5: ELCI2104: Elci has no String.length; a String is UTF-8 text; Bytes.length (Bytes.fromString s) is its byte lengthsrc/Main.elm:6:5: ELCI2104: Elci has no Bytes.lessThan; bytes are comparable: write a < bUsing a core module that isn’t imported by default, such as Bytes, Dict, Map, Array or
Julc.Data, without its import names the import to add:
src/Main.elm:6:5: ELCI2104: Bytes.fromString needs the Bytes module; add `import Bytes`A module imported with an alias is used through the alias:
src/Main.elm:8:5: ELCI2104: Map is imported as M; write M.getsrc/Main.elm:8:5: ELCI2104: Shop.Pricing is imported as P; write P.priceOfELCI2104 also covers exposing (..) on a Java module, a file whose module line does not match its
path, and import cycles:
src/Main.elm:3:1: ELCI2104: Java modules cannot be imported with exposing (..); list the exported names you usesrc/Pricing.elm:1:1: ELCI2104: Module header Finance.Pricing does not match its source path, which names module Pricingsrc/Pricing.elm:3:1: ELCI2104: Import cycle: Main -> Pricing -> MainCore module names are reserved, for modules and for aliases (see reserved names):
src/String.elm:1:1: ELCI2104: The module name String is taken by Elci's core library; rename this modulesrc/Tx.elm:1:1: ELCI2104: The module name Tx is taken by Elci's core library; rename this modulesrc/Set.elm:1:1: ELCI2104: The module name Set is reserved for Elci's core library; rename this modulesrc/Main.elm:3:1: ELCI2104: The alias String names a core module that every module imports; choose another alias for UtilsModules whose names start with Elci. belong to the core library too, and the ones it uses internally
can’t be imported: ELCI2104: Elci.Assoc is internal to Elci's core library; use Map or Dict, and
ELCI2104: Elci.Value is internal to Elci's core library; use Value. A Value has no constructors to
expose: import Julc.Ledger exposing (Value(..)) gives
ELCI2104: Value has no approved constructors or patterns; its values come from the Value module.
A name that two imports expose, one of them possibly a default import, is ELCI2102 where you use it:
src/Main.elm:8:5: ELCI2102: max is ambiguous: it could be Basics.max or Utils.max. Write the one you mean, like Basics.max, or stop exposing the otherAn ambiguous type name is reported at the declaration whose annotation uses it:
src/Main.elm:6:1: ELCI2102: The type Order is ambiguous: it could be Basics.Order or Shop.Order. Write the one you mean, like Basics.Order, or stop exposing the otherFix: import the module, correct the name (Map.get, not lookup), rename your module or alias, or
qualify one of the ambiguous names. Listing the name explicitly, as in import Utils exposing (max), also
resolves a clash with a default import.
ELCI2105: unsupported Java export
Section titled “ELCI2105: unsupported Java export”main : Intmain = case Math.divMod 7 2 of _ -> 0src/Main.elm:8:10: ELCI2105: org.julclang.stdlib.lib.MathLib.divMod: Unsupported on-chain source type: Tuple2<BigInteger, BigInteger>
8| case Math.divMod 7 2 of ^^^^^^^^^^^Fix: use another export, such as Math.floorDiv and Math.floorMod, or Elci operators.
An export whose result can hold a ledger Value, directly or in a field of a record or union, is rejected
too. Java libraries such as ValuesLib build values in their own order, and Elci relies on every value
being canonical. Julc’s ContextsLib and OutputLib are exempt, because they only pass along the ledger’s
own values:
src/Main.elm:9:5: ELCI2105: org.julclang.stdlib.lib.ValuesLib.add: returns a Value, which Java libraries do not keep in the ledger's canonical order; use the core Value moduleFix: use the core Value module, here Value.add. See
Java libraries for every reason an export can be rejected.
Code generation errors
Section titled “Code generation errors”ELCI3001: type is not known where it is used
Section titled “ELCI3001: type is not known where it is used”A type that nothing in the program determines, such as the element type of [], is fine for most code:
List.length [] is 0 and Julc.Data.encode [] is an empty list, as in Elm. Operations that create a
value of the type need to know it. These are Julc.Data.decode and generic Java library functions:
import Julc.Data as Data
main : Intmain = List.length (Data.decode (Data.encode [ 1, 2 ]))src/Main.elm:8:18: ELCI3001: Cannot determine the type converted by Julc.Data.decode; add a type annotation
8| List.length (Data.decode (Data.encode [ 1, 2 ])) ^^^^^^^^^^^List.length works on any list, so nothing tells Elci what the decoded list contains, and it cannot pick
a decoder. Fix: give the value a type:
main : Intmain = let amounts : List Int amounts = Data.decode (Data.encode [ 1, 2 ]) in List.length amountsA generic Java library function needs its type arguments. When a core module such as Map uses one
at a type nothing in your program determines, the error is reported at your call:
src/Main.elm:8:5: ELCI3001: `Map.size` is used here at a type that is not known (Map a b -> Int); add a type annotation, for example to a let bindingThat one comes from Map.size Map.empty; annotate the map (noPrices : Map String Int).
ELCI3002: specialization limit
Section titled “ELCI3002: specialization limit”A program may create at most 256 specializations of its generic functions. This happens with polymorphic recursion that inference did not already reject. Fix: make the recursive function monomorphic.
ELCI3003: no Data encoding
Section titled “ELCI3003: no Data encoding”Generic Java methods and Julc.Data conversions need a type with a Data encoding:
src/Main.elm:8:5: ELCI3003: Type argument T = Unit of firstOr must have a Plutus Data encoding (DATA_ENCODABLE); functions, unit and native values do notsrc/Main.elm:12:13: ELCI3003: No strict decoder for org.julclang.ledger.TxOut: The library provider cannot supply decode_strict record TxOut: [JULC0051] Library request decode_strict record TxOut is not supported: org.julclang.ledger.TxOut does not approve DECODE_STRICTEncoding a function names the reason:
import Julc.Data as Data
double : Int -> Intdouble x = x * 2
main : Intmain = List.length [ Data.encode double ]src/Main.elm:13:19: ELCI3003: No encoder for Int -> Int: functions have no Data encoding
13| List.length [ Data.encode double ] ^^^^^^^^^^^Fix: use a Data-encodable type. Functions, () and Array have no encoding, and TxOut can’t be
decoded. A Value converts on its own, but a type that contains one can’t be decoded yet, and a list or
tuple of values can’t be encoded: convert them with Value.toList and back with Value.fromList.
A Java library’s generic function can’t be used at a type that contains a Dict. The library could build
the dictionary itself and skip the check that its keys are in order:
src/Main.elm:14:18: ELCI3003: Type argument a = Dict Int Int of filter contains a Dict, which a Java library cannot keep sorted; pass a Map or a List and build the Dict with Dict.fromListFix: pass the library a Map or a List, and build the Dict with Dict.fromList. A type that holds
a Value is rejected the same way:
src/Main.elm:9:5: ELCI3003: Type argument a = Value of filter contains a Value, which a Java library does not keep in the ledger's canonical order; build it with the Value moduleUse the core List and Value modules instead.
Configuration and backend errors
Section titled “Configuration and backend errors”ELCI4001: configuration or command line
Section titled “ELCI4001: configuration or command line”elci: ELCI4001: unknown validator 'treasury'; configured: mainelci: ELCI4001: eval runs an [entrypoint] function; test validators with elci testelci: ELCI4001: parameter owner is not a well-formed org.julclang.ledger.PubKeyHash valueelci: ELCI4001: parameter caps has a Dict whose keys are not strictly ascending; write its keys sorted and without repeatselci: ELCI4001: src/Main.elm is not valid UTF-8 text; save it as UTF-8The message says what to change. A source file must be UTF-8 text. A Dict parameter must list its keys in ascending order, each once; see
parameterized validators.
Mistakes in elci.toml, in the arguments of elci init and on the command line have this code too:
elci: ELCI4001: Unknown configuration key: [project] nameelci: ELCI4001: Unsupported purpose: lend; expected spend, mint, withdraw, certify, vote, propose or functionelci: ELCI4001: Unknown option: --frobelci: ELCI4001: the [entrypoint] function main is not defined in module Mainelci: ELCI4001: my-project/elci.toml not found; a project needs an elci.toml, which elci init createselci: ELCI4001: Source directory not found: my-project/libelci: ELCI4001: library-jars file my-project/libs/pricing.jar not foundelci: ELCI4001: No source file for module Nope; add Nope.elm under a source directoryA problem with one validator’s table names the table after the code:
elci: ELCI4001: my-project/elci.toml:6: [validators.main]: Handler Main.spent for spend: module Main does not declare spentelci: ELCI4001: my-project/elci.toml:6: [validators.main]: Handler Vault.spend for spend: no source module Vaultelci: ELCI4001: my-project/elci.toml:6: [validators.main]: [java-modules] may not map Value, a module name of Elci's core libraryThe CLI and elci.toml references list the others. A
few errors have no code yet; they are listed below.
ELCI4002 and ELCI4003: backend
Section titled “ELCI4002 and ELCI4003: backend”ELCI4002 means Julc’s PIR verifier rejected the code Elci generated. It is reported at the Elci
declaration involved and keeps Julc’s own JULC00xx code in the message. ELCI4003 means the Julc
backend in use lacks a capability the program needs, which happens only with a mismatched Julc build.
Both point at a compiler problem rather than a mistake in your code: please report them with the
program that triggers them.
Errors without a code
Section titled “Errors without a code”Three errors from reading a Java library are still reported without a code or location. Each is printed
after elci:, and in the JSON report its code is null:
| Message | Cause |
|---|---|
On-chain Java source not found: org.julclang.stdlib.lib.NopeLib | An imported [java-modules] class that does not exist. |
Cannot resolve type: ?. Supported types: ... | A Java library that uses a wildcard type such as JulcList<?>. |
Unknown type: T. Did you mean: Vote? | A Java library that declares a parameterized record such as Box<T>. |