# Diagnostic codes

Every diagnostic has a code, a primary span in a file you own, the expected
and actual facts, and a fix when one is known; see
[check](https://sexpgpu.041.io/docs/check.md#where-a-diagnostic-points). `W-*` codes are warnings and
never stop a compilation. `sexpgpu check <file> --json` gives the same as
an array.

## Reading and evaluating

| code | what it means | usual fix |
|---|---|---|
| `E-READ-001` | end of input inside a form or a string | close the bracket or the quote |
| `E-READ-002` | an unexpected `)` or `]` | remove it, or open the form it closes |
| `E-READ-003` | a token that is not a number, keyword or symbol | `0.5` not `.5`; `:` plus a name for a keyword |
| `E-EVAL-001` | the program called `(error ...)` | read the message |
| `E-EVAL-002` | an `(assert ...)` failed | read the message |
| `E-EVAL-003` | a name is not bound; a knob used before its `defknobs` lands here | the fix names the module that defines it, or the nearest name |
| `E-EVAL-004` | calling something that is not a function | check the head of the call |
| `E-EVAL-005` | a malformed special form, lambda list, or a binding of reserved syntax | use the documented shape; see [special forms](https://sexpgpu.041.io/docs/special-forms.md) |
| `E-EVAL-006` | an argument of the wrong type, a bad destructuring, a bad dtype keyword | check the operand |
| `E-EVAL-007` | integer overflow or division by zero | |
| `E-EVAL-010` | a keyword argument that is not a keyword, unknown, or has no value | the fix lists the accepted keywords |
| `E-EVAL-011` | the wrong number of arguments | |
| `E-EVAL-030` | a file requires itself | move the shared definitions into a third file |
| `E-EVAL-031` | a required file cannot be read | paths are relative to the file holding the `require` |
| `E-EVAL-032` | a require path is neither relative nor a package | `./name.sx`, or `sexpgpu/<module>` |
| `E-EVAL-033` | no such standard module | the fix lists the ones that exist |
| `E-EVAL-034` | a `require` names nothing or is in a local scope | list names, at module top level |
| `E-EVAL-035` | a `require` names what the file does not define | the fix is the nearest name it does |
| `E-EVAL-036` | a name bound twice in one file, by two imports or an import and a definition | rename, or import once |
| `E-EVAL-040` | recursion deeper than 256 calls | no tail calls; check the base case, or use `repeat`/`reduce` |
| `E-EVAL-041` | compile-time work budget exceeded or invalid | raise `SEXPGPU_EVAL_LIMIT` for finite generators |

## Tensors and staging

| code | what it means | usual fix |
|---|---|---|
| `E-DIM-001` | shapes do not fit | the note names both operands as you wrote them |
| `E-DIM-002` | dtypes differ, or `:x` is not a dtype | dtypes are `:f32 :bf16 :i32 :i64 :bool` |
| `E-DIM-003` | a tensor was expected | |
| `E-FLOW-001` | `if` on a tensor | select elementwise with `(where test then else)` |
| `E-FLOW-002` | a tensor from another graph | recompute it here |
| `E-FLOW-003` | a tensor operation with no graph being traced | tensors exist in `prepare`, a model, `objective`, `evaluate`, an optimizer body, an initializer or `curriculum` |

## Models and optimizers

| code | what it means | usual fix |
|---|---|---|
| `E-PARAM-002` | `defparam` outside a model | parameters live inside `defmodel` |
| `E-PARAM-003` | an initializer reads another value | an initializer is closed: shapes, constants, random nodes |
| `E-PARAM-004` | a model body does not end in a function | return `(lambda (x) ...)` last |
| `E-PARAM-005` | `named` on something that is not a model or a parameter | |
| `E-PARAM-006` | an unknown parameter option, or `:numerics` other than `:high` | the options are `:tags` and `:numerics` |
| `W-PARAM-001` | a model is never bound to a name | bind it with `let`, or `named` |
| `E-OPT-001` | a selector matches no parameter | check paths with `sexpgpu explain`, or widen the glob |
| `E-OPT-002` | a parameter is in more than one group | narrow one selector with `select-not` |
| `E-OPT-003` | a misplaced or duplicate state, or a state initializer that is not a zero constant | return `zeros`, `zeros-like` or a zero `full` |
| `E-OPT-004` | an optimizer body does not end in `optimizer-update`, or drops a state | return every declared state exactly once |
| `E-OPT-005` | a malformed `select`, `group`, `:groups` or `:optimizer`, or an inner optimizer with `:groups` | the fix prints the shape |
| `E-OBJ-001` | `objective` does not return one float scalar | reduce the loss; report the parts with `metric` |

## The contract

| code | what it means | usual fix |
|---|---|---|
| `E-CONTRACT-001` | a required top-level name is missing | the fix writes the form that defines it, `(defrun :steps 300 :microbatches 4)`; see [the run file](https://sexpgpu.041.io/docs/run-file.md) |
| `E-CONTRACT-002` | a contract name is the wrong kind of value | the fix writes the form that defines it |
| `E-CONTRACT-003` | an unknown keyword in a configuration form, or a bad `:precision` | the fix lists the accepted ones |
| `E-CONTRACT-004` | `prepare` did not return `:inputs` and `:targets` | `(list :inputs ... :targets ...)` |
| `E-CONTRACT-005` | the batch has no such field | the fix lists what the loader declares |
| `E-CONTRACT-010` | `counter` outside `prepare` | count where records are counted |
| `E-CONTRACT-011` | `metric` in an optimizer body | a `diagnostic`, or compute it in `objective` or `evaluate` |
| `E-CONTRACT-012` | a metric's metadata is over what Metrics accepts, runtime keys counted | fewer or shorter keys |
| `E-CONTRACT-013` | two `defeval` passes share a name | |
| `E-CONTRACT-014` | `evaluate` or `curriculum` with no `defeval` pass | declare a pass |
| `E-CONTRACT-015` | a `diagnostic` without `:reduce`, with an unknown one, or two reducers for one name | one of `:mean :min :max :sum` |
| `E-CONTRACT-016` | a diagnostics selection that names nothing the file defines | the fix lists the names |
| `E-CONTRACT-017` | a `metric` inside a `tap-gradient` lambda | report the gradient with `diagnostic` |

## Knobs

| code | what it means | usual fix |
|---|---|---|
| `E-KNOB-001` | a knob is declared twice | |
| `E-KNOB-003` | a variant or sweep sets something that is not a knob | the fix lists the knobs |
| `E-KNOB-004` | the file declares no such variant | the fix lists the variants |
| `E-KNOB-005` | the file declares no such knob | the fix lists the knobs |
| `E-KNOB-006` | a duplicate variant, or one after `defknobs` | declare variants once, before `defknobs` |

## Run time and tools

| code | what it means | usual fix |
|---|---|---|
| `E-DP-001` .. `E-DP-007` | several GPUs or nodes: configuration, rendezvous and resume | see [devices](https://sexpgpu.041.io/docs/devices.md#several-gpus) |
| `E-MEM-001` | the smallest memory plan does not fit on the device; the message names the number and the largest part | fewer rows per microbatch (raise `:microbatches`), or a device with more memory; see [devices](https://sexpgpu.041.io/docs/devices.md#memory) |
| `E-FMT-001` | the formatter refused its own output | a compiler bug; the file was left as it was |
| `E-INTERNAL-001` | the lowered document failed validation | a compiler bug, never the experiment's fault |

---

SexpGPU documentation. Every page: https://sexpgpu.041.io/llms.txt
