Documentation
Diagnostics cookbook
Ten errors the compiler reports, each with a broken snippet, the exact message, the cause, and the fix. Find the message you got below.
The two base models
Every entry below starts from one of two small working models and breaks one thing. The broken and fixed snippets show only the sections that change; the rest of the model stays as written here. Each compiler message is copied verbatim from compiling the broken variant.
Base model A is a patch-only fire spread. Base model B is a pet model: grazing sheep with one action.
base model A — fire (patches)
world: x: -20..20 y: -20..20 topology: box params: density: number = slider(62, 0..100) patches: state: empty | tree | burning | burned = empty setup: patches: state := if (random-float(100) < density) then tree else empty where (tree and px = min-x): state := burning step staged: patches: where burning: state := burned where (tree and any neighbors4 where burning): state := burning stop when (count patches where burning = 0)base model B — grazing (pets)
world: x: -20..20 y: -20..20 topology: torus patches: has-grass: boolean = true pets: sheep: energy: number = 0 actions: graze: energy := energy + 1 patch.has-grass := false setup: create sheep 30 sheep: set-random-position step: sheep: forward(1) where (patch.has-grass): graze where (energy < 0): die1. A declaration section after a lifecycle section
In base model A, params: was moved between setup: and step staged:.
broken
setup: patches: state := if (random-float(100) < density) then tree else empty where (tree and px = min-x): state := burning params: density: number = slider(62, 0..100) step staged: patches: where burning: state := burnedcompiler output
Agent updates use `agentset:` or `agentset where (...):` followed by indented actions. Statement: `params:` Declarations in `params:` use `name: type = value`. Statement: `density: number = slider(62, 0..100)`
Declaration sections (world:, params:, monitors:, patches:, pets:, …) must all come before the lifecycle sections (setup:, step:, stop when). Once the parser is inside a lifecycle section, a bare params: line can only be read as an agent-update header, so the message talks about agentsets rather than ordering. If a diagnostic complains about an agentset on a line where you wrote a section header, check the section order first.
fixed
params: density: number = slider(62, 0..100) setup: patches: state := if (random-float(100) < density) then tree else empty where (tree and px = min-x): state := burning step staged: patches: where burning: state := burned2. An agent block not indented under its step
In base model B, the sheep: block header lost its indentation under step:.
broken
step:sheep: forward(1) where (patch.has-grass): graze where (energy < 0): diecompiler output
Lines inside `step:` must be indented. Statement: `sheep:`.
Sections own their bodies through indentation. A line at column zero is a new top-level section header, and sheep is not a section name, so the parser reports the un-indented line instead. Indent the whole agent block two spaces so it belongs to the step.
fixed
step: sheep: forward(1) where (patch.has-grass): graze where (energy < 0): die3. stop when without parentheses
In base model A, the parentheses around the stop condition were dropped.
broken
stop when count patches where burning = 0compiler output
Assignments in `setup:` and `step:` use `:=`, not `=`. For example: `patches:` followed by an indented `state := tree`. Statement: `stop when count patches where burning = 0`
The stop condition must be in parentheses: stop when (...). Without them the grammar rejects the whole line, and because the line contains a bare =, the message guesses you meant an assignment, which is misleading here. If this message points at a stop when line, the fix is the parentheses, not the operator.
fixed
stop when (count patches where burning = 0)4. Calling patch-here() instead of the patch property
In base model B, the sheep step tests the patch underfoot with the old function form.
broken
step: sheep: forward(1) where (patch-here().has-grass): grazecompiler output
`patch-here()` was renamed — use the `patch` property (e.g. `patch.has-grass`).
patch is a property of the current pet, like x, y, and heading, not a function call. The old patch-here()form was removed because the parentheses were misleading: it took no arguments and returned a writable reference. Older MathPets sources and habits from NetLogo's patch-here still produce it, so the compiler keeps a targeted message.
fixed
step: sheep: forward(1) where (patch.has-grass): graze5. Calling the removed kill-one command
In base model B, the sheep step removes a sheep on the same patch with the old bundled predation helper.
broken
step: sheep: forward(1) where (energy < 0): die kill-one(sheep, energy, 5)compiler output
kill-one was removed — write `let prey = one-of breed here` followed by `where (prey): kill(prey)`.
kill-one hid three decisions in one call: which agent to pick, whether one was there at all, and what the killer gains. The replacement spells out each one: one-of picks, where (prey): handles the empty-patch case, and the energy gain is a plain assignment you can change on its own.
fixed
step: sheep: forward(1) where (energy < 0): die let prey = one-of sheep here where (prey): kill(prey) energy := energy + 56. A zero-parameter action declared with parentheses
In base model B, the graze action was declared with an empty parameter list.
broken
pets: sheep: energy: number = 0 actions: graze(): energy := energy + 1 patch.has-grass := falsecompiler output
Zero-parameter action "graze" must be declared without parentheses.
The rule across the language is parentheses if and only if the call has arguments. graze takes none, so it is declared and called bare, like the built-in commands die and set-random-position. The opposite mistake is caught too: calling an action that takes parameters without parentheses reports Parameterized action "graze" must be called with parentheses.
fixed
pets: sheep: energy: number = 0 actions: graze: energy := energy + 1 patch.has-grass := false7. Calling an action the breed does not define
In base model B, the step calls munch but the action is declared as graze.
broken
step: sheep: forward(1) where (patch.has-grass): munchcompiler output
Unknown pet action "munch" for agentset "sheep".
A bare identifier used as a statement inside a pet block is read as an action call. So this message covers more than typos: it also appears when you call an action declared on a different breed, or when a field name stands alone on a line. Check the actions: block of the breed named in the message; the action must be declared there or in the shared pets:-level actions: block.
fixed
step: sheep: forward(1) where (patch.has-grass): graze8. Movement commands inside step staged
In base model B, the sheep step was declared step staged: while still calling forward(1) and die.
broken
step staged: sheep: forward(1) where (patch.has-grass): graze where (energy < 0): diecompiler output
Staged steps do not support pet commands. Use a non-staged step for movement.
step staged: is the two-phase mode: every read sees the state from before the section, and writes commit together at the end, which is what cellular-automaton rules need. Pet commands such as forward, hatch, and die are not supported there. Keep patch rules staged and put movement in a plain step:; a model can declare both, and they run in source order each tick.
fixed
step staged: patches: where (not has-grass and random-float(100) < 3): has-grass := true step: sheep: forward(1) where (patch.has-grass): graze where (energy < 0): die9. self outside an agent context
In base model B, a monitor tries to read a field through self.
broken
monitors: my-energy: number = self.energycompiler output
self is not valid in observer contexts.
Monitors, observer-level setup statements, and stop when run as the observer, so there is no current agent for self to refer to. self is only valid inside an agent update block or an action body. At the observer level, aggregate over the agentset instead.
fixed
monitors: mean-energy: number = mean sheep report (energy)10. Testing a lookup against undefined
In base model B, the grass check was written the way a JavaScript author would guard a possibly-missing value.
broken
step: sheep: forward(1) where (patch.has-grass != undefined): grazecompiler output
there is no `undefined` in Pets — test the lookup itself: `where (not pet-at(...))`.
MathPets has no undefined or null; the value for a missing agent is nobody. A declared field always holds a value of its type, so test it directly. A lookup that can miss, such as one-of sheep here or pet-at(...), is false when it finds nothing, so guard it by testing the result itself in a where clause.
fixed
step: sheep: forward(1) where (patch.has-grass): graze # guarding a lookup that can miss: let prey = one-of sheep here where (prey): kill(prey)