Skip to content

Errors and Gotchas

Dimitri edited this page Aug 29, 2026 · 5 revisions

Errors

Two kinds, both printed into the console in red.

Compile errors happen before anything runs and abort the whole run:

[compile error] line 3: expected '{' after if condition

Runtime errors stop the program where it stood:

[error] line 12: index 5 out of range (length 3)

There is no try/catch and no way to trap an error. Defensive code checks first:

if len(parts) > 1 { print(parts[1]) }
let value = load("k")
if value == nil { print("not set") }

Common runtime errors: undefined variable 'x', expected a number, got string, division by zero, index N out of range, <fn> expects N argument(s), got M, nil is not callable, call stack overflow, unknown side 'x', unknown item 'x'.


Gotchas

  • 0 and "" are truthy. Use x == 0 or len(s) == 0 explicitly.
  • Assignment needs a prior let. x = 1 on a fresh name is a runtime error, not an implicit declaration.
  • No closures, no nested functions. Share state through globals.
  • < and friends are numbers only — you cannot compare strings with them (sort handles a list of strings, though).
  • Out-of-range indexing errors rather than returning nil; check len first.
  • Lists are shared references, so push(f(l), x) may mutate the caller's list. Copy with l + [] when you need a snapshot.
  • store stringifies. Numbers come back as strings; wrap reads in num().
  • A reloaded chunk restarts the program from line 1. Persist anything important to disk.
  • peers() includes this pot, so filter yourself out when iterating; broadcast already skips you.
  • Typing stop while a program is running halts it instead of feeding read().
  • sleep counts game ticks, not seconds — multiply seconds by 20.
  • Unloaded pots vanish from the network, and send to them returns false. Check the return value if delivery matters.
  • A bad item name is an error, not a 0. inv_count/inv_find/inv_move throw on anything not in the item registry, so a typo surfaces immediately.
  • inv_move lands in the same slot a hopper would. Which face you move into decides the slot — e.g. a furnace takes fuel from the side and input from above — it isn't free-for-all slot access.
  • sign_write blanks any line you don't supply. Passing a 2-element list clears lines 3 and 4, it doesn't leave them as-is.
  • entities() counts players too, typed as "minecraft:player" — filter them out if you only want mobs.
  • rs_pulse's countdown keeps running even if the program stops or the chunk unloads; only rs_set/rs_reset on that side cancels it early.
  • for walks the live list, not a copy. Pushing to the list you're iterating extends the loop; popping shortens it. Iterate l + [] for a snapshot.
  • rs_wait only sees changes while it's waiting. A pulse that starts and ends between two rs_wait calls (e.g. while the body is sleeping) is missed — keep the body short, or poll rs_get when you can't afford to miss edges.
  • hear only queues chat while the program runs, from players within 16 blocks, and the queue keeps the newest 16 lines. Commands aren't chat, and the pot never hears its own say.
  • The hologram outlives the program. display text stays up after the program stops or finishes; take it down with display() in the program, or reboot in the terminal.

See also: Examples · Wiki Home

Clone this wiki locally