Why Verse Fails #4 — Reading the Compiler
Unverified — this example may not compile as-is.
The Verse code below did not pass our automated compile check, so it isn't marked verified and is hidden from the guide listing. The explanation may still be useful, but treat the code as a draft and adapt it before use.
Overview
Three lessons ago, the compiler was the thing stopping you. By now you know better: it's the most honest teammate you have — it reads every line, forgets nothing, and tells you exactly which contract broke. This finale turns that relationship into a practice: the field guide to the errors you'll actually meet, each one real, each one captured from a real build, each one a thirty-second repair once you can read it.
One habit powers the whole guide — the fix loop: read the error's code and quoted term, find the position it points at, apply the family rule, recompile. No staring, no guessing, no deleting your afternoon's work. Let's walk the field, most-common first.
3506 — Unknown identifier (the one you'll meet most)
By a wide margin, the most common compile failure in real Verse projects is also the simplest: the compiler doesn't know a name because the module that defines it was never brought in.
using { /Verse.org/Simulation }
vault_missing_using := class(creative_device):
OnBegin<override>()<suspends> : void =
Print("Where is my device base class?")
Script error 3506: Unknown identifier `creative_device`.
Did you forget to specify using { /Fortnite.com/Devices }
Read the gift in that second line: the compiler names the exact fix. using { /Fortnite.com/Devices } at the top, and this file passes. When 3506 hits a name you didn't expect — a typo'd function, a class from a file you forgot to include — the repair is the same question: where does this name live, and can this file see it? (In a multi-file module, a 3506 on your own module's name usually means the files must be compiled together — the set is the unit, not the file.)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_missing_using := class(creative_device):
OnBegin<override>()<suspends> : void =
Print("Found my device base class")
3511 & 3512 — the contracts (your series spine)
You've mastered these. Thirty-second recaps:
- 3511 — round brackets on a
<decides>call. The brackets lie about the risk. Fix:HasKey[Agent], notHasKey(Agent). - 3512 — an effect not allowed by its context; read the quoted effect.
'decides'→ a might-fail question outside a failure context (lesson 1).'no_rollback'→ un-undoable work where rollback is required — almost always the silent unannotated default (lessons 2-3). Fix the contract, not the position.
3513 — expected an expression that can fail
The mirror image of 3512. An if condition wants a failable question — and you handed it a plain logic value, which can't fail, only be true or false:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_logic := class(creative_device):
var DoorOpen : logic = false
OnBegin<override>()<suspends> : void =
if (DoorOpen):
Print("Come on in")
Script error 3513: Expected an expression that can fail in the 'if' condition clause
The postfix ? turns a logic into exactly the failable question the condition wants — succeeds if true, fails if false:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_logic := class(creative_device):
var DoorOpen : logic = false
OnBegin<override>()<suspends> : void =
if (DoorOpen?):
Print("Come on in")
3581 — break is loop-only
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_break := class(creative_device):
Keys : []string = array{"Rusty", "Coral", "Gold"}
OnBegin<override>()<suspends> : void =
for (K : Keys):
if (K = "Coral"):
break
Print("done")
Script error 3581: This `break` is not in a breakable context. `break` may currently only be used inside a `loop`.
The compiler's sentence is the rule: break belongs to loop: — a for isn't a breakable context. When you want to stop a for early, restructure: put the walk in its own function and return on the hit —
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_break := class(creative_device):
Keys : []string = array{"Rusty", "Coral", "Gold"}
FindCoral() : void =
for (K : Keys):
if (K = "Coral"):
Print("Found it")
return
OnBegin<override>()<suspends> : void =
FindCoral()
Print("done")
3100 — the parser lost you (syntax shapes)
Errors in the 31xx range with vErr: codes aren't about effects or contracts — the parser literally couldn't read the line. The classic:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_spawn := class(creative_device):
Tick()<suspends> : void =
Sleep(1.0)
OnBegin<override>()<suspends> : void =
spawn Tick()
Script error 3100: vErr:S77: Unexpected "Tick" following expression
"Unexpected Tick following expression" is the parser telling you spawn didn't parse the way you meant — it needs braces: spawn{ Tick() }. When a 31xx error baffles you, look for a shape problem on the exact line: missing braces, a stray token, indentation that broke the block.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_spawn := class(creative_device):
Tick()<suspends> : void =
Sleep(1.0)
OnBegin<override>()<suspends> : void =
spawn{ Tick() }
3596 — attributes go on the macro (and a lesson in cascades)
Specifiers care about placement. <concrete> describes what the struct is, so it belongs on the struct macro — not on the name:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_cfg := module:
wave_config<public><concrete> := struct:
Size : int = 3
vault_struct := class(creative_device):
OnBegin<override>()<suspends> : void =
Print("config ready")
Script error 3596: Attribute concrete should be used on the struct macro name, like `s := struct<concrete> ...`.
Again the error text carries its own fix — s := struct<concrete> — and the repair is moving one token:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vault_cfg := module:
wave_config<public> := struct<concrete>:
Size : int = 3
vault_struct := class(creative_device):
OnBegin<override>()<suspends> : void =
Print("config ready")
Now the advanced read. Here's the same mistake in a file that also has an @editable field of that struct type:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
wave_config_f1<public><concrete> := struct:
Zombies<public> : int = 8
wave_board_f1 := class(creative_device):
@editable
Waves : []wave_config_f1 = array{}
One broken line, two errors. The misplaced attribute means the struct isn't concrete — so the @editable array of it fails too, five lines away. This is a cascade, and it's why the field guide's last rule matters most: fix the FIRST error and recompile. The 3604 here isn't a second bug; it's the shadow of the first. Chasing errors bottom-up wastes afternoons; top-down, half of them vanish on the first fix.
The field guide on one card
| You see | It means | You do |
|---|---|---|
| 3506 unknown identifier | a name this file can't see | add the using the error names; in multi-file modules, compile the set |
| 3511 parentheses on decides | brackets lie about risk | call with [] |
| 3512 'decides' not allowed | a question with no failure plan | move it into a failure context |
| 3512 'no_rollback' not allowed | un-undoable work where rollback is required | annotate the pure helper <transacts>; leave world-touchers undecorated |
| 3513 expected failable expression | plain logic in a condition |
postfix ? |
| 3581 break not breakable | break outside loop: |
restructure — return from a function, or use loop: |
| 31xx vErr | the parser lost the shape | fix the line's syntax (spawn{}, braces, indentation) |
| 3596 attribute placement | specifier on the wrong slot | move it to the macro: struct<concrete> |
| several errors at once | possibly a cascade | fix the FIRST, recompile, reassess |
Where you stand
Four lessons ago, a wall of red output meant a bad afternoon. Now: failure is a feature with places that plan for it; every function carries a contract, and the silent default is the trap to name on sight; folk rules fall to gate evidence; and every error in this guide is a repair you've already made. The compiler was never fighting you. It was teaching — you just needed the reading lessons. Welcome to fluency.
Get the complete code — free
You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.
Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.
Check your understanding
Test yourself with an interactive quiz and track your progress + earn XP — free for members.
Turn this into a guided course
Add The error-code field guide: 3506/3511/3512/3513/3581/3100/3596 + cascade-reading, every string captured from real builds to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.
Original lesson generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.