Overview
failure-context-required is not a placed device — it's the single most common compiler error a new Verse creator hits, and it comes straight from the heart of the language. In Verse, an expression that might fail (like unwrapping an optional player, checking team membership, or indexing an array) can only be written inside a failure context: a place where the language already knows what to do on both success and failure.
Think of the sunny cove dock: a weapon crate should only open for a player who is (1) actually present — a real agent unwrapped from an ?agent payload — and (2) on the correct team. Each of those checks can fail. If you write them out in the open, the compiler stops you with "This expression must appear within a failure context." The fix is never to guess an API — it's to wrap the failable work in a context like an if.
Reach for this knowledge whenever you subscribe to an event that hands you a ?agent, whenever you call a <decides> method like IsOnTeam, or whenever you index into an array. All of those are failable and all of them need a home.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Here's the cove-dock crate. A PlayerAddedEvent from the playspace fires when someone arrives on the island. We check whether that arriving player is on the crate's owner team — a failable IsOnTeam[...] call — and only then unlock the crate prop. Every failable step lives inside an if failure context.
using { /Fortnite.com }
using { /Fortnite.com/Playspaces }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# The sunny cove-dock crate gate.
cove_crate_gate := class(creative_device):
# The crate prop sitting on the dock. Hidden until an allowed player arrives.
@editable
CratePropMesh : creative_prop = creative_prop{}
OnBegin<override>()<suspends>:void =
# Grab the playspace and its team collection ONCE.
Playspace := GetPlayspace()
TeamCollection := Playspace.GetTeamCollection()
# Subscribe to arrivals. PlayerAddedEvent hands us a `player` payload.
Playspace.PlayerAddedEvent().Subscribe(OnPlayerArrived)
# Also check everyone already on the island at start.
for (P : Playspace.GetPlayers()):
OnPlayerArrived(P)
# Event handler: this is a METHOD at class scope, subscribed above.
OnPlayerArrived(Arrival : player) : void =
Playspace := GetPlayspace()
TeamCollection := Playspace.GetTeamCollection()
# THIS is the failure context. Every failable call lives inside the if.
# GetTeam[...] fails if the player is on no team; IsOnTeam[...] is <decides>.
# GetTeams() returns an array we index with [0] — indexing is failable too.
if:
AllTeams := TeamCollection.GetTeams()
FirstTeam := AllTeams[0]
TeamCollection.IsOnTeam[Arrival, FirstTeam]
then:
# Only reached when ALL of the above succeeded.
OpenCrate()
OpenCrate() : void =
# A non-failable side effect — safe outside a failure context.
CratePropMesh.Show()
Line by line:
@editable CratePropMesh : creative_prop = creative_prop{}— you MUST declare the prop as an editable field to touch it from Verse; a bare reference is 'Unknown identifier'.Playspace.PlayerAddedEvent().Subscribe(OnPlayerArrived)—PlayerAddedEvent()is alistenable(player), so the handler receives aplayer, not a?player. We subscribe a class method.- Inside
OnPlayerArrived, theif:block is the failure context.AllTeams[0](array indexing), andIsOnTeam[Arrival, FirstTeam](a<decides>method, written with[]) are all failable. - If any of the three lines in the
iffails, the whole context fails andthen:never runs — the crate stays shut. That is failure driving control flow. OpenCrate()callsCratePropMesh.Show(), a plain non-failable effect, so it lives safely outside any failure context.
Common patterns
Pattern 1 — Unwrapping an ?agent payload. Many device events hand you an optional agent. The unwrap A := MaybeAgent? is failable and needs a failure context (the if).
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
dock_trigger_gate := class(creative_device):
@editable
DockTrigger : trigger_device = trigger_device{}
@editable
RewardProp : creative_prop = creative_prop{}
OnBegin<override>()<suspends>:void =
DockTrigger.TriggeredEvent.Subscribe(OnStepped)
# TriggeredEvent hands a ?agent. Unwrapping it is failable.
OnStepped(MaybeAgent : ?agent) : void =
if (Agent := MaybeAgent?):
# Inside the failure context we now have a real agent.
RewardProp.Show()
Pattern 2 — for as a failure context with a filter. The iteration and filter clauses of a for are themselves a failure context, so you can drop failable checks right into the loop head.
using { /Fortnite.com }
using { /Fortnite.com/Playspaces }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
shore_team_counter := class(creative_device):
@editable
CountedProp : creative_prop = creative_prop{}
OnBegin<override>()<suspends>:void =
Playspace := GetPlayspace()
TeamCollection := Playspace.GetTeamCollection()
if (FirstTeam := TeamCollection.GetTeams()[0]):
# The filter `TeamCollection.IsOnTeam[P, FirstTeam]` is failable
# and legal because a `for` head IS a failure context.
for (P : Playspace.GetPlayers(), TeamCollection.IsOnTeam[P, FirstTeam]):
ShowForOne()
ShowForOne() : void =
CountedProp.Show()
Pattern 3 — a <decides> helper function is its own failure context. The body of a function marked <decides> is a failure context, so failable expressions are allowed directly in it; callers must then invoke it with [].
using { /Fortnite.com }
using { /Fortnite.com/Playspaces }
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
clifftop_vault := class(creative_device):
@editable
VaultDoor : creative_prop = creative_prop{}
OnBegin<override>()<suspends>:void =
Playspace := GetPlayspace()
Playspace.PlayerAddedEvent().Subscribe(OnArrived)
# <decides> makes this function's body a failure context.
IsAllowed(P : player)<transacts><decides>:void =
Playspace := GetPlayspace()
TeamCollection := Playspace.GetTeamCollection()
Team := TeamCollection.GetTeam[P] # failable, allowed here
TeamCollection.IsOnTeam[P, Team] # failable, allowed here
OnArrived(P : player) : void =
# Call the <decides> helper with [] inside an if failure context.
if (IsAllowed[P]):
VaultDoor.Show()
Gotchas
<decides>means brackets, not parens. A method likeIsOnTeamandGetTeamare<decides>, so you call themIsOnTeam[...]/GetTeam[...], and only inside a failure context. Using()on them is a compile error.- Array indexing can fail.
MyArray[0]fails if the array is empty. That's whyGetTeams()[0]must sit inside anif/forhead — it isn't 'safe'. ?unwrap is failable.MaybeAgent?on a?agentneeds a failure context; you cannot use the result until anif (A := MaybeAgent?):succeeds.- Effects don't belong in the condition of an
ifunless failable. Put non-failable side effects (Show(),Hide()) in thethen:body, not in the failure-context condition. PlayerAddedEvent()gives aplayer, not?agent. No unwrap needed there — but that sameplayerstill needs a failure context when you check its team.- Whole context rolls back on failure. If a later line in an
ifcondition fails, earlier speculative effects are undone — this is intended, not a bug. Rely on it for all-or-nothing gates. - There is no
StringToMessage. If a device method wants amessage, declareMyText<localizes>(S:string):message = "{S}"and passMyText("...")— unrelated to failure contexts but a frequent companion error.