Error Codes

Some eucalypt diagnostics carry a stable code such as EU-EVAL-TYPE, shown in the diagnostic header (error[EU-EVAL-TYPE]: ...) and in the code field of --error-format json output. A code is stable across releases: once assigned, it identifies the same category of problem even if the wording of the message changes, so it is safe to match on in scripts, editor integrations, or your own notes.

Not every diagnostic has a code yet — codes are being added incrementally, category by category. A diagnostic without a code is still fully described by its message, source location, and notes; see Error Messages Guide for how to read those.

Codes are namespaced by area: EU-<AREA>-<SLUG>, e.g. EU-EVAL-TYPE for a runtime evaluation error, EU-PARSE-* for a parser error, EU-NAME-* for name resolution, EU-TYPE-* for a type-checker warning.

Look up a code from the command line with eu error <CODE>, e.g. eu error EU-EVAL-TYPE prints the catalogue entry below. This is independent of eu explain <FILES>, which explains what a run would do given input files rather than looking up a code.

Catalogue

EU-EVAL-TYPE

What it means: a value of one type was used where a different type was required — for example, a string was passed to an arithmetic operator that expects a number, or a number was used where a block was expected. This is a runtime error: the mismatch was only discovered when the value was evaluated.

Example:

a: "3"
result: a + 1
error[EU-EVAL-TYPE]: type mismatch: expected number, found string "3"
  ┌─ example.eu:2:11
  │
2 │ result: a + 1
  │           ^
  │
  = to convert a string to a number, use 'num', e.g. 's num'
  = to concatenate strings, use string interpolation or 'str.join-on' instead of '+'

How to fix it: convert the value to the type the operator expects before using it — for example, a num + 1 converts the string to a number first. See the prelude reference for the conversion functions available for each type (num, str, str.of, and so on).

EU-EVAL-CONTRACT

What it means: data failed a structural contract applied with ensure. The contract is an ordinary type spec written as an s"…" literal, and the diagnostic's notes list every position that did not conform, each with a path into the data. The source location is the ensure call site — the contract that failed — while the paths in the notes say where in the data to look.

Example:

{ import: "contract.eu" }
schema: s"{ name: string, port: number }"
config: { name: "web", port: "8080", debug: true } ensure(schema)
error[EU-EVAL-CONTRACT]: contract violation: 2 violations against {name: string, port: number}
  ┌─ example.eu:3:51
  │
3 │ config: { name: "web", port: "8080", debug: true } ensure(schema)
  │                                                   ^^^^^^^^^^^^^^
  │
  = port: expected number, found string
  = (root): unexpected keys: debug

How to fix it: correct the data at each path the notes name, or widen the spec if the shape you are receiving is the shape you intended — a closed record spec such as {name: string} reports surplus keys, and adding .. ({name: string, ..}) permits them. To inspect the violations as data rather than aborting, call validate(spec, data) instead: it returns the same information as a list of blocks and never raises. See the Contracts guide.

EU-RENDER-UNREPRESENTABLE

What it means: a value survived evaluation intact, but the output format you asked for has no way to carry it. The commonest case is an integer above 9223372036854775807 (the signed 64-bit maximum): JSON, EDN and eucalypt itself carry it happily, but a YAML integer scalar and a TOML integer are both signed 64-bit. TOML also has no null, so a null value cannot be rendered as TOML either.

Example: given big.json holding {"n": 9999999999999999999},

` { target: :main output: :yaml import: "data=big.json" }
main: data.n
error[EU-RENDER-UNREPRESENTABLE]: cannot represent this value in YAML output: the integer 9999999999999999999 is above 9223372036854775807, the largest integer a YAML integer scalar can carry
  ┌─ example.eu:2:7
  │
2 │ main: data.n
  │       ^^^^^^
  │
  = render to a format that can carry the value — 'json', 'edn', 'text' and 'eu' output all keep integers of this magnitude
  = to keep the exact digits in this format, convert the value to a string first with 'str', e.g. 'n str'

How to fix it: render to a format that can carry the value — -x json, -x edn, -x text and -x eu all keep integers of this magnitude — or convert it to a string first with str, so the exact digits are preserved as text. For a null being rendered as TOML, give the key a value or drop it from the block before rendering. eucalypt reports this rather than quietly rounding the value or changing its type, so that what you export matches what you evaluated.

EU-RENDER-SHAPE

What it means: the output format needs the document to have a particular structure, and the value being rendered does not have it. Two cases raise it.

Whole-document shape. html output renders hiccup markup — a list whose first item is the tag, optionally followed by an attribute block and then contents — so rendering a block, or a bare scalar, has no meaning as html.

Block keys. json, toml and eu output all need block keys to be text: JSON object keys and TOML keys are strings, and eucalypt's own syntax needs a name. Block literals always have symbol keys, but kv-block and block accept any key at all, so kv-block(1, "a") — or a boolean, list or block key — produces a block those three formats cannot render. yaml and edn both represent such keys (1: a and {1 "a"} respectively) and render the block unchanged. The type checker warns on such a key too (type mismatch calling 'kv-block'), so this diagnostic confirms a mistake already flagged rather than refusing something idiomatic.

Example (document shape):

` { target: :main format: :html }
main: { a: 1 b: 2 }
error[EU-RENDER-SHAPE]: cannot render this document as html: the value to render is a block, but markup output needs a hiccup element — a list whose first item is the tag
  = html output renders hiccup markup: a list of tag, attribute block and contents, e.g. '[:div, { id: "top" }, "hello"]'
  = select the markup value with a target or '-e', e.g. 'eu -x html -e page.eu'; rendering a whole unit gives html the unit's block, which is not markup
  = to render arbitrary data instead, choose a format that accepts any shape, such as 'yaml', 'json' or 'text'

Example (block key):

` { target: :main format: :json }
main: kv-block(1, "a")
error[EU-RENDER-SHAPE]: cannot render this document as JSON: a block key is the number 1, but JSON object keys must be text
  = give the block symbol keys, e.g. 'kv-block(:one, "a")', or convert the key to text with 'str' before rendering
  = 'yaml' and 'edn' output both support keys that are not text, and render this block unchanged

How to fix it: for a shape mismatch, build the value as hiccup markup, e.g. [:div, { id: "top" }, "hello"], and select it with a target or -e so that html is given the markup itself rather than the enclosing unit's block. For a block key, give the block symbol keys — e.g. kv-block(:one, "a") — or convert the key to text with str before rendering. In either case you can instead choose a format that accepts the document as it stands: yaml, json or text for arbitrary shapes, and yaml or edn for keys that are not text.

eucalypt reports this rather than coercing the value — a key rendered as "1" is not the key that was evaluated, and the difference survives into anything that re-reads the output.

This diagnostic often has no source location: the document's root events are emitted by the render pipeline rather than by a user expression, and a literal block key records no annotation, so there is frequently no span to point at.