Goblin Error Messages
Below is a comprehensive list of every Goblin error message. If you encounter an error, you should be given a link to the exact error message on this page. You can also use the sidebar links to find what you are looking for. In each entry, you'll get the error code, the name of the error message, what type it is, when it occurs, at least one example of incorrect code, and then at least one example of how to fix it. If you still have questions, feel free to ask them in the Goblin subreddit.
A0401 — unknown-action
Category: runtime / actions
When it happens: An action name is called that is not defined, exported, or built in.
Example
call("does_not_exist", 1, 2) /// or does_not_exist(1, 2)
call("does_not_exist", 1, 2) /// or does_not_exist(1, 2)
How to fix: Check the action name and imports. Define the action, or import the module that exports it.
FS0001 — filesystem-io
Category: runtime / filesystem error
When it happens: A filesystem operation fails (e.g., create_dir!, file writes/reads) due to OS-level issues such as permission denied, invalid path, missing drive, or a locked file/dir.
Example
/// Permission denied or invalid path create_dir!("/root/protected") /// Windows example: invalid/locked path create_dir!("C:\Windows\System32\config\SAM")
/// Permission denied or invalid path create_dir!("/root/protected") /// Windows example: invalid/locked path create_dir!("C:\Windows\System32\config\SAM")
How to fix:
- Use a path you have permission to create or run the process with sufficient privileges.
- Ensure the path is valid on the current OS (watch for illegal characters or reserved names).
- If a parent directory is on an unmounted/missing volume, mount or correct the drive/path.
- If another process holds a lock, retry after it releases the handle.
- Prefer
create_dir!with an existing/accessible parent;create_dir!is idempotent when the directory already exists.
J0001 — json-parse-failed
Category: runtime / JSON
When it happens: The string passed to json_parse (or read via read_json) is not valid JSON.
Example
json_parse("{ name: 'Alf' }") <---- missing quotes around key, wrong quotes for strings
json_parse("{ name: 'Alf' }") <---- missing quotes around key, wrong quotes for strings
How to fix: Provide well-formed JSON: double-quoted keys/strings, proper commas/braces.
json_parse("{ \"name\": \"Alf\" }")
json_parse("{ \"name\": \"Alf\" }")
J0002 — json-stringify-failed
Category: runtime / JSON
When it happens: Converting a value to JSON with json_stringify/json_stringify_pretty fails (e.g., value contains unsupported/recursive structures).
Example
let x = seq_new(backend: "weird"); json_stringify(x) <---- backend not serializable to JSON
let x = seq_new(backend: "weird"); json_stringify(x) <---- backend not serializable to JSON
How to fix: Convert or remove non-serializable parts before stringifying. Serialize only plain values (numbers, strings, arrays, maps, booleans, nil).
J0003 — json-io
Category: runtime / IO
When it happens: read_json(path) cannot read the file (not found, permissions) or similar IO errors.
Example
read_json("./missing.json") <---- file not found
read_json("./missing.json") <---- file not found
How to fix: Ensure the path is correct and readable. Check permissions and working directory.
J0004 — json-write-io
Category: JSON / I/O error
When it happens: Writing JSON to a file fails (e.g., missing directory, insufficient permissions, read-only path, disk full, or an invalid path string).
Example
/// Directory doesn't exist write_json!("/no/such/dir/data.json", { a: 1 }) /// Or path isn't a string let p = 123 write_json!(p, { a: 1 })
/// Directory doesn't exist write_json!("/no/such/dir/data.json", { a: 1 }) /// Or path isn't a string let p = 123 write_json!(p, { a: 1 })
How to fix:
- Pass a valid string for the path (e.g.,
"out/data.json"). - Ensure the directory exists or create it before writing.
- Check file permissions and that the path isn't read-only.
- Make sure there's enough disk space and the file isn't locked by another process.
- On Windows, avoid reserved names (e.g.,
CON,PRN) and ensure the path is valid.
M0001 — mutation-operator-required
Category: meta / mutation required
When it happens: A mutating operation is called without the bang form (!). In Goblin, side-effecting actions (like writing files or creating directories) must use the bang form to signal intent.
Examples
/// These will raise M0001 write_json("out.json", data) create_dir("logs/")
/// These will raise M0001 write_json("out.json", data) create_dir("logs/")
/// Use the bang form for mutations write_json!("out.json", data) create_dir!("logs/") /// Optional pretty-print for JSON write_json!("out.json", data, true)
/// Use the bang form for mutations write_json!("out.json", data) create_dir!("logs/") /// Optional pretty-print for JSON write_json!("out.json", data, true)
How to fix:
Use the bang (!) variant of the operation whenever it causes side effects (filesystem writes, directory creation, etc.).
Notes:
- Non-mutating counterparts (without
!) may either not exist or are intentionally disallowed to prevent accidental side effects. - The bang form makes intent explicit and easier to audit in code reviews.
M0002 — not-callable
Category: meta / callability error
When it happens: You try to "call" a value that isn't an action/function (e.g., a number, string, map, array, or any non-callable value).
Examples
let x = 42 x() <---- not callable let s = "hello" s(1) <---- not callable let a = [1, 2] a(0) <---- not callable # Passing a non-action as the action parameter map([1,2,3], 5) <---- second arg must be an action name (string)
let x = 42 x() <---- not callable let s = "hello" s(1) <---- not callable let a = [1, 2] a(0) <---- not callable # Passing a non-action as the action parameter map([1,2,3], 5) <---- second arg must be an action name (string)
How to fix:
- Call only declared actions or built-ins.
- Ensure variables you call actually refer to actions.
- If an API expects an action name, pass it as a string, e.g.
map([1,2,3], "double"). - Refactor data (numbers/strings/maps/arrays) so they are arguments to actions, not the callee.
Correct usage
action double(n) { n * 2 } map([1,2,3], "double") <---- calls the action named "double" print("hello") <---- built-in callable
action double(n) { n * 2 } map([1,2,3], "double") <---- calls the action named "double" print("hello") <---- built-in callable
P0314 — expected-array
Category: parser / type error
When it happens: This error occurs when Goblin expects an array expression but receives a different type, such as a single value or object.
Example
sum(42) <---- error: expected an array of expressions sum([1, 2, 3]) <---- correct sum(1, 2, 3) <---- correct
sum(42) <---- error: expected an array of expressions sum([1, 2, 3]) <---- correct sum(1, 2, 3) <---- correct
How to fix:
Wrap multiple values in square brackets [] to create an array. Use commas to separate elements.
Correct examples:
values = [10, 20, 30] process(values)
values = [10, 20, 30] process(values)
P0330 - invalid-number-literal
Category: parse
When it happens: A malformed number literal was encountered — for example, multiple decimal points or invalid characters.
Example
x = 12.3.4
x = 12.3.4
How to fix: Use valid numeric syntax:
42 3.1415 1_000_000 6.02e23
42 3.1415 1_000_000 6.02e23
P0340 — invalid-dice-notation
Category: parse
When it happens: Dice notation could not be parsed due to a missing d, malformed modifier, or unexpected character.
Example
roll("2x6") <---- invalid — should be 2d6 roll("d20") <---- invalid — missing count before d roll("2d6++") <---- invalid modifier
roll("2x6") <---- invalid — should be 2d6 roll("d20") <---- invalid — missing count before d roll("2d6++") <---- invalid modifier
How to fix: Ensure dice notation follows valid forms such as:
2d6 4d10+2 3d8-1 2d20+adv 5d6k3 1d500 3d12!1
2d6 4d10+2 3d8-1 2d20+adv 5d6k3 1d500 3d12!1
P0341 — dice-notation-invalid
Category: parser
When it happens: The string passed to roll_str or roll_detail_str is not valid dice notation.
Examples
roll_str("2d") <---- missing sides roll_str("d6") <---- missing count roll_str("2x6") <---- unknown delimiter roll_detail_str("") <---- empty string
roll_str("2d") <---- missing sides roll_str("d6") <---- missing count roll_str("2x6") <---- unknown delimiter roll_detail_str("") <---- empty string
Valid forms (examples):
"1d20""3d6+2""4d8-1""2d10k1"(keep highest 1)"5d6!2"(drop lowest 2)
How to fix: Ensure the dice string matches a supported pattern (e.g., NdS, optionally with modifiers like +N, -N, khX, klX, dhX, dlX).
Help: Provide a non-empty string using recognized dice notation, then call roll_str or roll_detail_str with that value.
P0802 — lvalue-expected
Category: parser error
When it happens: The parser expected a valid lvalue — a variable name or a field access — but found a different kind of expression.
Examples
/// invalid: left side is not a variable/field set (a + b) = 3 /// invalid: not a name or field access set 42 = x
/// invalid: left side is not a variable/field set (a + b) = 3 /// invalid: not a name or field access set 42 = x
How to fix: Use a plain identifier or a field access as the target.
total = a + b user >> name = "Ada"
total = a + b user >> name = "Ada"
P0804 — field-name-required
Category: parser error
When it happens: A field name (identifier) is required immediately after the >> operator, but something else (or nothing) is provided.
Example
>> 123 <---- not an identifier >> "name" <---- string, not an identifier >> <---- missing field name
>> 123 <---- not an identifier >> "name" <---- string, not an identifier >> <---- missing field name
How to fix: Provide a valid identifier after >>.
>> name >> next_field
>> name >> next_field
P1408 — pick-missing-source
Category: parse/config error
When it happens: A pick call is made without specifying a source collection (from <collection> / src) or a numeric form (e.g., range_start/range_end or digits). The runtime cannot determine what to pick from.
Example
/// No source and no numeric range/digits pick /// Has count but missing 'src' and numeric config pick 1
/// No source and no numeric range/digits pick /// Has count but missing 'src' and numeric config pick 1
How to fix: Provide either:
- a collection source via
src, e.g. an array/seq/map, or - a numeric configuration via
range_start/range_end
Correct examples
/// From a collection pick 2 from ["red", "green", "blue"] /// From a numeric range (exclusive upper bound) pick 1 from 1..5 <---- pick 1 number between 1 and 4 /// From a numeric range (inclusive upper bound) pick 1 from 1...5 <---- pick 1 number between 1 and 5 /// Generate d-digit numbers pick 1_4 <---- pick 1 4-digit number
/// From a collection pick 2 from ["red", "green", "blue"] /// From a numeric range (exclusive upper bound) pick 1 from 1..5 <---- pick 1 number between 1 and 4 /// From a numeric range (inclusive upper bound) pick 1 from 1...5 <---- pick 1 number between 1 and 5 /// Generate d-digit numbers pick 1_4 <---- pick 1 4-digit number
Help: Decide what domain you want to sample from. Use src for collections, or range_*/digits for numbers.
P9001 — readonly-field
Category: parser / immutability rule
When it happens: You attempt to modify a field that is marked as read-only (immutable) in the type or record definition.
Examples
user42|User = { id!: 42, name: "Sam" } <---- assume `id` is readonly user42.id = 7 <---- P9001: cannot modify readonly field 'id'
user42|User = { id!: 42, name: "Sam" } <---- assume `id` is readonly user42.id = 7 <---- P9001: cannot modify readonly field 'id'
/// Inside a pipeline/update where `status` is readonly order >> status = "shipped" <---- P9001
/// Inside a pipeline/update where `status` is readonly order >> status = "shipped" <---- P9001
How to fix:
- Don't assign to the readonly field. Update a different, mutable field.
- Construct a new value instead of mutating:
user7|User = { id: 7, name: "Sara"}
user7|User = { id: 7, name: "Sara"}
- If the field shouldn't be readonly, change the definition (remove the readonly qualifier) in the type/module that declares it.
Message text: cannot modify readonly field '<id>'
R0000 — not-implemented
Category: internal-error
When it happens: A feature or function has not yet been implemented.
Example
future_magic_feature()
future_magic_feature()
How to fix: Check Goblin's release notes or documentation for upcoming implementations.
R0009 — internal-assign-slot
Category: internal error
When it happens: This occurs when Goblin cannot locate an existing variable slot during an assignment operation. It indicates a logic or state error inside the interpreter.
Example
/// Internal runtime error example (should not occur in normal Goblin code)
/// Internal runtime error example (should not occur in normal Goblin code)
How to fix: This is not user error. Report the issue with the source file and stack trace to the Goblin maintainers for investigation.
R0101 — unknown-ident
Category: runtime / name resolution error
When it happens: You reference a variable or name that hasn't been declared/bound in the current scope (and isn't in any outer scope or module export).
Examples
say foo <---- 'foo' was never declared x = 10 say y <---- 'y' does not exist act f() => say z <---- is unknown inside f
say foo <---- 'foo' was never declared x = 10 say y <---- 'y' does not exist act f() => say z <---- is unknown inside f
How to fix:
- Declare/bind the variable before using it.
- Check for typos (e.g.,
fo0vsfoo). - Ensure the name is in scope (import or qualify it if it lives in a module). (If the name is not in scope, you will get a warning to shadow.)
Fixed examples
foo = 42 say foo <---- ok
foo = 42 say foo <---- ok
import game/hero as h h::generate_hero() <---- qualify with module name/alias if you need to use an action from the module
import game/hero as h h::generate_hero() <---- qualify with module name/alias if you need to use an action from the module
R0111 — duplicate-local
Category: runtime / binding error
When it happens: Triggered when attempting to declare a variable that already exists in the current scope using the shadow operator incorrectly.
Example
x = 5 x [= 10 <---- error: 'x' already declared in this scope
x = 5 x [= 10 <---- error: 'x' already declared in this scope
How to fix:
Use = to reassign an existing variable or choose a new name. If you intend to shadow the variable, use [= in a different scope, not the same one.
R0113 — immutable-assign
Category: runtime / assignment error
When it happens: Occurs when trying to reassign a value that was declared immutable using imm.
Example
imm x = 42 x = 10 <---- error: cannot reassign immutable 'x'
imm x = 42 x = 10 <---- error: cannot reassign immutable 'x'
How to fix:
Remove the imm keyword if you want to allow reassignment, or create a new variable with a different name.
R0114 — outer-scope-shadow
Category: runtime / scope error
When it happens: Raised when you try to declare a new variable in a local scope that already exists in an outer scope, without explicitly shadowing it.
Example
x = 1 act test x = 2 <---- error: 'x' exists in an outer scope; use '[=' to shadow end
x = 1 act test x = 2 <---- error: 'x' exists in an outer scope; use '[=' to shadow end
How to fix:
If you intend to create a new local variable, use [= to shadow the outer one. Otherwise, reassign the existing one with =.
R0115 — namespace-not-found
Category: runtime / name-resolution error
When it happens: You use the namespace operator :: with an identifier that isn't a declared module or enum in scope. The engine can't resolve the left-hand side as a valid namespace.
Examples
/// 'Math' was never declared as a module or enum x = Math::sqrt(9) /// 'Color' exists as a value, not as an enum type y = Color::Red /// Misspelled module name import game/hero as h s = he::title("hi") <---- typo: 'h'
/// 'Math' was never declared as a module or enum x = Math::sqrt(9) /// 'Color' exists as a value, not as an enum type y = Color::Red /// Misspelled module name import game/hero as h s = he::title("hi") <---- typo: 'h'
How to fix:
- Make sure the left side of
::is a declared module or enum that's in scope. - Import it (
import foo/bar) or fully qualify the path. - If it's an enum variant you want, reference the correct enum type.
- Check for typos.
Corrected
/// Module exists import data/locations x = locations::get_location(location) /// Proper enum type enum Color { Red, Green } y = Color::Red
/// Module exists import data/locations x = locations::get_location(location) /// Proper enum type enum Color { Red, Green } y = Color::Red
R0116 — unknown-class
Category: runtime
When it happens: Code references a class name that isn't defined or registered in the current session (e.g., typo in the type tag, missing import/registration, or the class wasn't declared with @ClassName = ...).
Example
/// Typo: 'Usr' instead of 'User' alice|Usr = { name: "Alice", email: "alice@example.com" }
/// Typo: 'Usr' instead of 'User' alice|Usr = { name: "Alice", email: "alice@example.com" }
How to fix: Declare the class, then use the correct name.
@User = name: {name} email: {email} end alice|User = { name: "Alice", email: "alice@example.com" }
@User = name: {name} email: {email} end alice|User = { name: "Alice", email: "alice@example.com" }
Also check:
- Spelling of the class name in type tags (e.g.,
bob|User). - That the module defining the class was imported/loaded before use.
- Build/registration order if classes are registered programmatically.
R0117 — unknown-enum
Category: runtime / name resolution
When it happens: Code references an enum type that is not declared, not imported, or out of scope.
Example
x = Color::Red <---- 'Color' enum was never declared/imported
x = Color::Red <---- 'Color' enum was never declared/imported
How to fix:
- Declare the enum before use, or import it from the module where it is defined.
- Check for typos in the enum name.
- Ensure the current module has visibility to the enum (exports/imports).
R0118 — unknown-variant
Category: runtime / name resolution
When it happens: The enum exists, but the referenced variant name does not exist on that enum.
Example
enum Color { Red, Green } x = Color::Blue <---- 'Blue' is not a variant of 'Color'
enum Color { Red, Green } x = Color::Blue <---- 'Blue' is not a variant of 'Color'
How to fix:
- Use one of the defined variants of the enum.
- Add the missing variant to the enum definition if it's intended to exist.
- Check for typos or wrong enum/variant pairing.
R0200 — numeric-expected
Category: type-error
When it happens: A numeric value was required, but another type was provided.
Example
big("hello")
big("hello")
How to fix: Pass a valid numeric type (int, float, big, or pct) instead of non-numeric data.
R0201 — type-mismatch-runtime
Category: type-error
When it happens: A numeric value was expected, but a non-numeric type was provided at runtime.
Example
sqrt("hello")
sqrt("hello")
How to fix: Provide a numeric value such as int, float, big, or pct.
R0203 — big-exponent-range
Category: runtime / math error
When it happens: pow(base, exp) uses Big math and the exponent is a Big integer that cannot fit into a signed 64‑bit integer.
Example
pow(big(2), big(10_000_000_000_000)) <---- exponent too large for integer Big pow
pow(big(2), big(10_000_000_000_000)) <---- exponent too large for integer Big pow
How to fix: Reduce the exponent to a 64‑bit range, or switch to floating‑point exponentiation when non‑integer or very large exponents are needed.
R0206 — division-by-zero
Category: math-error
When it happens: Division by zero was attempted, or zero was used as the base of a negative exponent.
Example
0 / -1
0 / -1
How to fix: Avoid dividing by zero or using zero as a base in negative powers.
R0207 — math-domain
Category: runtime / math error
When it happens: Invalid numeric domain, e.g., calling sqrt() on a negative value.
Example
sqrt(-1) <---- error: cannot take square root of a negative value
sqrt(-1) <---- error: cannot take square root of a negative value
How to fix:
Validate inputs before calling the function (e.g., ensure non‑negative for sqrt). Use abs() or conditional checks as appropriate.
R0212 — invalid-cast-big
Category: invalid-cast
When it happens: A value cannot be safely converted to a decimal (Big).
Example
big(true)
big(true)
How to fix: Use a valid numeric or numeric string such as big("0.1") or big(1.25).
R0223 — percent-string-big
Category: invalid-string
When it happens: A string with a trailing '%' was passed to big().
Example
big("12.5%")
big("12.5%")
How to fix: Use pct(12.5) instead, or remove % and scale manually before conversion.
R0224 — invalid-numeric-string-big
Category: invalid-string
When it happens: big() received a string that is not a valid decimal number.
Example
big("12.3.4") big("abc")
big("12.3.4") big("abc")
How to fix: Provide a valid numeric string like big(1234.50).
Digits with one decimal point are allowed; underscores are ignored.
R0298 — float-to-decimal-failed
Category: conversion-error
When it happens: Conversion from Float or Percent to Decimal failed due to overflow or invalid representation.
Example
big(1e400)
big(1e400)
How to fix: Use smaller, representable numbers when converting to Big (Decimal).
R0301 — wrong-arity
Category: call-error
When it happens: A function or action was called with the wrong number of arguments.
Example
some_action(1, 2, 3) <---- expected other than 3 arguments
some_action(1, 2, 3) <---- expected other than 3 arguments
How to fix: Provide the correct number of parameters expected by the action.
R0302 — missing-argument
Category: runtime / call error
When it happens: Anaction is called without providing all required positional arguments, and no default value exists for the missing parameter.
Example
act greet(name, title) say "Hello {title} {name}!" end /// Missing 'title' greet("Alice")
act greet(name, title) say "Hello {title} {name}!" end /// Missing 'title' greet("Alice")
How to fix: Provide all required arguments when calling the action or define default values for optional parameters.
R0313 — precision-loss-float
Category: precision-error
When it happens: A value too large (≥ 2⁵³) or non-finite decimal cannot be safely represented as a float.
Example
float(99999999999999999)
float(99999999999999999)
How to fix: Use big() for exact precision, or round/truncate before conversion.
R0314 — invalid-cast-float
Category: invalid-cast
When it happens: A string or value cannot be parsed or converted into a valid float.
Example
float(12.5%) float("abc")
float(12.5%) float("abc")
How to fix: Use pct(12.5) or 12.5% for percentages or pass a valid numeric.
R0316 — invalid-cast-int
Category: invalid-cast
When it happens: A value cannot be cast to an integer (non-numeric or invalid string).
Example
int("hello")
int("hello")
How to fix: Pass a valid numeric or numeric-string value such as int(42) or int("123").
R0320 — invalid-big-to-pct
Category: invalid-cast
When it happens: The value passed to pct() is a Big number that cannot be represented as a float.
Example
pct(1e400)
pct(1e400)
How to fix: Use smaller or representable numeric values. For extremely large decimals, consider scaling manually.
R0321 — invalid-pct-string
Category: invalid-string
When it happens: The string passed to pct() is not a valid numeric or percent string.
Example
pct("abc%")
pct("abc%")
How to fix: Use a valid numeric string such as pct("12.5") or pct("75").
R0322 — invalid-pct-cast
Category: invalid-cast
When it happens: The value cannot be cast to a percent (unsupported type).
Example
pct(true)
pct(true)
How to fix: Only numeric, percent, or string values can be used with pct(). Convert other types before calling.
R0325 — non-finite-float
Category: math-error
When it happens: A non-finite float (NaN or Infinity) was encountered during a Big (Decimal) math operation.
Example
big(1/0)
big(1/0)
How to fix: Ensure the value is finite before performing Big math operations.
R0326 — big-overflow
Category: conversion-error
When it happens: A Big (Decimal) number was too large or precise to fit into a 64-bit float.
Example
float(999999999999999999999999999999999999999)
float(999999999999999999999999999999999999999)
How to fix: Use Big math or reduce the number's precision before converting to float.
R0401 — invalid-index
Category: type-error
When it happens: A non-integer or negative value is provided where a non-negative integer index is expected.
Example
arr = [10, 20, 30] arr[-1] <---- invalid — negative index arr[2.5] <---- invalid — fractional index arr["one"] <---- invalid — string index
arr = [10, 20, 30] arr[-1] <---- invalid — negative index arr[2.5] <---- invalid — fractional index arr["one"] <---- invalid — string index
R0402 — array-expected
Category: runtime / collection error
When it happens: A builtin expecting a single array argument (e.g., sum, avg, min/max in single-argument form) receives a non-array value.
Example
avg(42) <---- error: 42 is not an array min(1) <---- error: single-arg form expects an array
avg(42) <---- error: 42 is not an array min(1) <---- error: single-arg form expects an array
How to fix: Wrap values in an array and pass that array as the single argument.
Correct examples:
sum([1, 2, 3]) avg([10, 20, 30]) min([x, y, z])
sum([1, 2, 3]) avg([10, 20, 30]) min([x, y, z])
R0403 — no-such-field
Category: object-error
When it happens: Attempting to access a field or member that doesn't exist.
Example
user >> age
user >> age
How to fix: Ensure the field name exists in the object's class definition.
R0404 — empty-array
Category: runtime / collection error
When it happens: min([..]) or max([..]) is called with an empty array.
Example
min([]) <---- error: min of empty array max([]) <---- error: max of empty array
min([]) <---- error: min of empty array max([]) <---- error: max of empty array
How to fix:
Ensure the array has at least one element before calling min/max, or handle the empty case separately.
R0405 — loop-control-outside-loop
Category: runtime / control-flow error
When it happens: skip or stop is executed while not inside a looping construct.
Examples
/// not inside a loop skip
/// not inside a loop skip
/// also not inside a loop stop
/// also not inside a loop stop
How to fix:
Wrap the control statement inside a loop (while, for, or repeat), or remove it.
repeat 3 if x < 0 skip say x end end
repeat 3 if x < 0 skip say x end end
while x < 10 if x == 5 stop end x = x + 1 end
while x < 10 if x == 5 stop end x = x + 1 end
Help: Use skip to continue to the next iteration and stop to exit the current loop—but only from within a loop body.
R0410 — malformed-bound-action
Category: runtime / object method binding
When it happens: The runtime encounters a "bound action" (method wrapper) map that is missing the required name string field. This usually means a bound method object was constructed incorrectly or corrupted before use.
Example
m = { kind: "bound_action" } /// missing name call(m) <---- → R0410
m = { kind: "bound_action" } /// missing name call(m) <---- → R0410
How to fix:
- Don't hand-craft bound action objects; let the language create them via normal member access (e.g.,
obj.method). - If you're generating or transforming these objects, ensure they include a string
namefield (and other required fields) before calling.
Notes: Bound actions are internal wrappers that capture a receiver and the method name for later invocation. Missing or mistyped fields make the wrapper invalid.
R0411 — relation-value-required
Category: runtime
When it happens: An of relation field (foreign key) is required during object construction, but no value was provided and the field is not nullable.
Example
@Post = title: Str of User as author <---- non-nullable relation end /// Missing `author` value p|Post = { title: "Hello" }
@Post = title: Str of User as author <---- non-nullable relation end /// Missing `author` value p|Post = { title: "Hello" }
u|User = { name: "Alice", email: "alice@example.com" } p|Post = { title: "Hello", author: u } <---- object with id /// or p|Post = { title: "Hello", author: u >> id } <---- explicit id (string)
u|User = { name: "Alice", email: "alice@example.com" } p|Post = { title: "Hello", author: u } <---- object with id /// or p|Post = { title: "Hello", author: u >> id } <---- explicit id (string)
R0500 — unclosed-interp-brace
Category: parse / interpolation-error
When it happens: This occurs when an interpolated string (one containing {}) starts with a { but does not contain a matching closing brace }. It can also appear when braces are malformed or left unbalanced.
Example
say "Hello {name" /// ^ missing closing '}'
say "Hello {name" /// ^ missing closing '}'
How to fix:
Add a closing brace } to complete the interpolation, or escape literal braces using double braces {{ or }} if you intend to print them literally.
Correct examples:
say "Hello {name}" <---- interpolate variable say "Use {{ to print {" <---- literal brace
say "Hello {name}" <---- interpolate variable say "Use {{ to print {" <---- literal brace
R0501 — import-io
Category: runtime / I/O error
When it happens: This occurs when Goblin cannot determine or access the current working directory during an import. This may happen due to restricted permissions, a missing directory, or a sandboxed environment.
Example
import utils /// ^ error: cannot get current directory
import utils /// ^ error: cannot get current directory
How to fix: Ensure that the working directory exists and is readable. If running in a container, daemon, or restricted environment, verify that the process has permission to access the filesystem.
Correct examples:
cd /project/root /// then run goblin normally
cd /project/root /// then run goblin normally
R0502 — import-failed
Category: runtime / module resolution
When it happens: This error indicates that Goblin attempted to import a module or symbol but could not resolve or read it. This may be due to an incorrect path, missing file, or inaccessible module.
Example
import non_existent_module /// ^ module cannot be resolved
import non_existent_module /// ^ module cannot be resolved
How to fix: Check that the specified file or module exists and is accessible. Use absolute or correct relative paths. When importing named items, ensure they are exported from the target module.
Correct examples:
import data/helpers import math as m import parser as p
import data/helpers import math as m import parser as p
R0503 — op-not-meaningful
Category: runtime / collection error
When it happens: An operation is used that has no defined meaning for the target collection (e.g., put first on a map, which has no inherent order).
Example
a = {d: 1, e: 2} put_first!(a, 3) <---- maps don't have an ordered 'first'
a = {d: 1, e: 2} put_first!(a, 3) <---- maps don't have an ordered 'first'
How to fix:
Use operations that make sense for the type of collection. For maps, use key-based access such as at("key") instead of positional operations.
R0504 — op-not-implemented
Category: runtime / limitation
When it happens: The operation/position combination exists conceptually but hasn't been implemented yet (e.g., update where on maps).
Example
update_where!(is_even) {a:1, b:2} with 0 <---- not yet implemented for maps
update_where!(is_even) {a:1, b:2} with 0 <---- not yet implemented for maps
How to fix: Rewrite the logic using supported operations (like filtering and rebuilding), or wait for the feature to be implemented in a later version.
R0505 — op-not-supported
Category: runtime / operation error
When it happens: The combination of collection type, selector, and operation is unsupported (e.g., update all on strings).
Example
x = "abc" update_all!(x, "x") <---- unsupported operation for strings; this actually does work, though
x = "abc" update_all!(x, "x") <---- unsupported operation for strings; this actually does work, though
How to fix:
Use only supported operations: grab, put, update, or delete with positions like first, last, at(i), where(pred), or all.
R0701 — empty-collection
Category: runtime / collection error
When it happens: An operation requiring elements is used on an empty collection (e.g., grab first on an empty array or string).
Example
b = {} grab_first(b)
b = {} grab_first(b)
How to fix: Ensure the collection is non-empty before performing the operation, or handle the empty case explicitly using conditional logic.
R0702 — invalid-range-no-values
Category: runtime / range filtering error
When it happens: A numeric range combined with filters (e.g., digits, unique, or exclusivity) leaves no valid values to choose from. This typically occurs in functions like pick when the specified interval is empty or the constraints exclude every candidate.
Examples
/// Empty interval (exclusive end by default): 5..5 ⇒ no values pick 1 from 5..5 /// Filters eliminate all values: requires 1-digit numbers in a two-digit range pick 1_2 from 0...9 /// Too strict digit-uniqueness for a tiny range pick 3 from 100..102 unique
/// Empty interval (exclusive end by default): 5..5 ⇒ no values pick 1 from 5..5 /// Filters eliminate all values: requires 1-digit numbers in a two-digit range pick 1_2 from 0...9 /// Too strict digit-uniqueness for a tiny range pick 3 from 100..102 unique
How to fix:
- Widen the range or enable inclusion when appropriate.
- Loosen filters: reduce
digits, don't useuniqueor remove conflicting constraints. - Provide a different source (e.g.,
from <collection>) that actually contains eligible values.
R0703 — insufficient-distinct
Category: runtime / sampling error
When it happens: A request asks for more distinct items than exist in the collection or domain when duplicates are not allowed.
Examples
/// Not enough unique elements in the source array pick 4 from ["a", "b", "c"] without dups pick 3 from ["Sam", "Frodo"] /// Not enough unique values in range 1..3 when 4 are requested without replacement pick 4 from 1...3 without dups
/// Not enough unique elements in the source array pick 4 from ["a", "b", "c"] without dups pick 3 from ["Sam", "Frodo"] /// Not enough unique values in range 1..3 when 4 are requested without replacement pick 4 from 1...3 without dups
Why it fails: Without replacement (allow_dups: false), the maximum number of items you can draw equals the size of the source set. Asking for more would require duplicates, which are disallowed.
How to fix:
- Reduce
countto be ≤ the number of available unique items, or - Increase the size of the source (add more elements / widen the range), or
- Permit duplicates by setting
allow_dups: true.
Corrected
/// Reduce count pick 3 from ["a", "b", "c"] without dups /// Or allow duplicates pick 3 from ["Sam", "Frodo"] with dups /// Or widen the range pick 4 from 1...5 without dups
/// Reduce count pick 3 from ["a", "b", "c"] without dups /// Or allow duplicates pick 3 from ["Sam", "Frodo"] with dups /// Or widen the range pick 4 from 1...5 without dups
R0704 — sample-too-large
Category: runtime / collection sampling
When it happens: A sampling operation without replacement requests more items than exist in the source collection (e.g., pick/reap with without dups and count larger than the collection size).
Examples
/// not enough numbers in that range pick 4 from 1...3 without dups <---- sample-too-large: requested sample of 4 exceeds available 3 distinct values in range
/// not enough numbers in that range pick 4 from 1...3 without dups <---- sample-too-large: requested sample of 4 exceeds available 3 distinct values in range
/// Map (entries) m = { a: 1, b: 2 } pick 3 from m wo dups <---- sample-too-large: requested 3 entries but only 2 available
/// Map (entries) m = { a: 1, b: 2 } pick 3 from m wo dups <---- sample-too-large: requested 3 entries but only 2 available
How to fix:
- Reduce
countso it is ≤ the number of available items/entries when usingwithout dupsorwo dups. - Or set
with dupsto allow sampling with replacement.
Help:
- Use
len(collection)to check availability before sampling. - For maps, remember that availability is the number of key—value pairs (entries).
R0705 — single-die-required
Category: runtime / dice config error
When it happens: adv (advantage) or dis (disadvantage) is used with a roll where count ≠ 1.
Example
roll 3d20 +adv <---- error: R0705: single-die-required: adv/dis requires a single die (count=1)
roll 3d20 +adv <---- error: R0705: single-die-required: adv/dis requires a single die (count=1)
How to fix:
- Use exactly one die when enabling
advordis. - Or remove
adv/diswhen rolling multiple dice.
roll 1d20 +adv roll 3d20
roll 1d20 +adv roll 3d20
R0706 — invalid-option-combination
Category: runtime / dice config error
When it happens: Mutually exclusive options are provided together, e.g. keep_high and drop_low at the same time.
Example
roll 4d6k3x1
roll 4d6k3x1
How to fix:
- Choose only one of the conflicting options.
roll 4d6k3 roll 4d6x1
roll 4d6k3 roll 4d6x1
R0707 — reroll-eq-out-of-range
Category: runtime / dice config error
When it happens: reroll_eq is set to a face not possible for the die (e.g., outside 1..=sides).
Example
roll 2d6r0 <---- error: R0707: reroll-eq-out-of-range: reroll_eq must be between 1 and sides roll 2d6r7
roll 2d6r0 <---- error: R0707: reroll-eq-out-of-range: reroll_eq must be between 1 and sides roll 2d6r7
How to fix:
- Set
reroll_eqto a value between1andsidesinclusive.
roll 2d6r1
roll 2d6r1
R0708 — weights-len-mismatch
Category: runtime / weighted sampling error
When it happens: The length of weights does not match the length of the source collection passed to sample_weighted.
Example
sample_weighted({ src: ["A", "B", "C"], weights: [0.5, 0.5], count: 1 }) <---- error: R0708: length-mismatch: ‘weights’ length must match ‘src’.
sample_weighted({ src: ["A", "B", "C"], weights: [0.5, 0.5], count: 1 }) <---- error: R0708: length-mismatch: ‘weights’ length must match ‘src’.
How to fix:
- Provide one weight per item in
src. - Ensure both
srcandweightsare non-empty and aligned by index.
/// OK: same length sample_weighted({ src: ["A", "B", "C"], weights: [0.2, 0.3, 0.5], count: 1 })
/// OK: same length sample_weighted({ src: ["A", "B", "C"], weights: [0.2, 0.3, 0.5], count: 1 })
Notes:
weightsmust be numbers ≥ 0 and their total must be > 0 (separate validations).
R0902 — no-result
Category: no-result
When it happens: The REPL or evaluator finished without a final expression value to return.
Example
/// (empty line) /// or only statements that don't yield a value
/// (empty line) /// or only statements that don't yield a value
How to fix: Enter an expression that yields a value (e.g., 2 + 2), or assign then echo (x = 5 then x).
R0903 — return-arity-mismatch
Category: runtime / return value arity
When it happens: A call is used in a multi-target assignment (or destructuring) but the function returns a single value instead of the required number of values.
Example
/// Expects two values on the left side (x, y) = compute() /// ^^^^^^^ returns only one value
/// Expects two values on the left side (x, y) = compute() /// ^^^^^^^ returns only one value
How to fix:
- Make the function return exactly the number of values expected by the assignment; or
- Adjust the assignment to match what the function returns.
Corrected examples
# Option 1: return two values action compute() { stop (1, 2) } let (x, y) = compute()
# Option 1: return two values action compute() { stop (1, 2) } let (x, y) = compute()
# Option 2: match a single return value action compute() { stop 42 } let x = compute()
# Option 2: match a single return value action compute() { stop 42 } let x = compute()
T0202 — positive-int-expected
Category: type / runtime error
When it happens: A non-positive or non-integer value is supplied where a positive integer (≥ 1) is required (e.g., configuration fields like counts, sizes, or digits).
Example
# 'count' must be a positive integer pick { count: 0 } # non-integer pick { count: 2.5 } # other places that require positive integers roll { count: -3, sides: 6 } format(n, -1)
# 'count' must be a positive integer pick { count: 0 } # non-integer pick { count: 2.5 } # other places that require positive integers roll { count: -3, sides: 6 } format(n, -1)
How to fix: Provide an integer ≥ 1.
pick { count: 3 } roll { count: 2, sides: 6 } format(n, 2)
pick { count: 3 } roll { count: 2, sides: 6 } format(n, 2)
Help: Ensure the value is an integer and greater than or equal to 1. If you derived it from an expression, clamp or cast appropriately (e.g., max(1, x.i())).
T0203 — boolean-expected
Category: type / runtime error
When it happens: A non-boolean value (such as a number, string, or object) is used where a boolean (true or false) is required.
Example
if 5 { say "hello" }
if 5 { say "hello" }
How to fix: Ensure the value is a proper boolean or an expression that evaluates to one.
if true { say "hello" } # or if x > 5 { say "x is greater than 5" }
if true { say "hello" } # or if x > 5 { say "x is greater than 5" }
Help: Use true or false, or an expression that returns a boolean value.
T0204 — integer-expected
Category: type / runtime error
When it happens: A non-integer (e.g., a float like 3.5 or a string that doesn't parse to an integer) is provided where a whole number is required.
Typical trigger: Range bounds or similar parameters that must be whole numbers, e.g. range_start, range_end.
Example
pick({ range_start: 1.2, range_end: 10 }) # ^ not an integer
pick({ range_start: 1.2, range_end: 10 }) # ^ not an integer
How to fix: Provide whole numbers (integers) for the parameter.
pick({ range_start: 1, range_end: 10 })
pick({ range_start: 1, range_end: 10 })
Help: Use whole numbers for parameters that require integers (e.g., 1, 42, -7). Avoid decimals like 3.14 or strings that aren't clean integers.
T0205 — type-mismatch
Category: type-mismatch
When it happens: A value of the wrong type is used where a specific type (string or character) is expected.
Example
say(123) # expects a string grade = "AB" # expects a single char, not a multi-character string
say(123) # expects a string grade = "AB" # expects a single char, not a multi-character string
T0206 — non-nullable-field-required
Category: type
When it happens: A non-nullable field without a default wasn't provided during construction (named or positional).
Example
@User = name: Str # required email: Str? # nullable end u|User = { email: "a@example.com" } # missing `name`
@User = name: Str # required email: Str? # nullable end u|User = { email: "a@example.com" } # missing `name`
Error output
error: T0206: non-nullable-field-required: non-nullable field requires a value
└─ main.gbln:7:1
7 | u|User = { email: "a@example.com" }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: Field 'name' is required and has no default.
= help: Provide a value explicitly or add a default.
= link: https://goblinlang.org/docs/errors#T0206
How to fix: Provide the field or define a default.
u|User = { name: "Alice", email: "a@example.com" } # or @User = name: Str = "Anon" email: Str? end
u|User = { name: "Alice", email: "a@example.com" } # or @User = name: Str = "Anon" email: Str? end
T0207 — non-nullable-field-nil
Category: type
When it happens: nil was provided for a non-nullable field during construction.
Example
@User = name: Str # non-nullable bio: Str? end u|User = { name: nil } # invalid: name is non-nullable
@User = name: Str # non-nullable bio: Str? end u|User = { name: nil } # invalid: name is non-nullable
Error output
error: T0207: non-nullable-field-nil: cannot assign nil to non-nullable field
└─ main.gbln:7:1
7 | u|User = { name: nil }
| ^^^^^^^^^^^^^^^^^^^^
= help: Field 'name' is non-nullable.
= help: Provide a non-nil value or mark the field as nullable.
= link: https://goblinlang.org/docs/errors#T0207
How to fix: Provide a value or change the field to nullable (Str?).
u|User = { name: "Alice" }
u|User = { name: "Alice" }
T0208 — object-or-array-expected
Category: type
When it happens: The right-hand side of object construction was not a map ({...}) or array ([...]).
Example
@User = name: Str end u|User = 42 # invalid construction
@User = name: Str end u|User = 42 # invalid construction
Error output
error: T0208: object-or-array-expected: object or array expected
└─ main.gbln:6:1
6 | u|User = 42
| ^^^^^^^^^
= help: Expected an object literal ('{...}') or array ('[...]') to construct 'User'. Got Int(42)
= help: Use named-field construction with a map or positional construction with an array.
= link: https://goblinlang.org/docs/errors#T0208
How to fix: Use either named-field or positional construction.
u|User = { name: "Alice" } # map # or u|User = [ "Alice" ] # array (positional)
u|User = { name: "Alice" } # map # or u|User = [ "Alice" ] # array (positional)