Handles, sockets, and resource references
Three kinds of connection often look alike in WolvenKit: an internal CR2W handle, a graph socket edge, and a path to another resource. They fail at different times and need different tests.
Identify the connection domain
| Connection | Typical form | Scope | Question |
|---|---|---|---|
| CR2W handle | HandleId / HandleRefId | One serialized CR2W object graph | Which object does this field own or reference? |
| Quest graph edge | Source socket to destination socket | One questphase graph | Which output causes execution to enter which input? |
| Scene graph stamp | Named/ordinal socket stamps and destinations | One scene graph | Which stamped route joins these nodes? |
| External resource | ResourcePath, often hard or soft | Virtual depot | Does the packed/registered resource exist at this exact path? |
| World identity | NodeRef | Streaming/world namespace | Is a loaded world resource registering this identity? |
A graph node ID is not its CR2W HandleId. A NodeRef is not either one. See
Identifier domains before editing a
number merely because it resembles another identifier.
Diagnose an internal handle failure
Symptoms include conversion errors, a missing nested object after round trip, an edge whose destination disappears, or a crash when a handled payload is first used.
- Serialize the binary back to an isolated review file.
- Inventory every
HandleIdand everyHandleRefIdin the affected CR2W. - Require each reference to resolve to exactly one compatible object.
- Check ownership: two fields may intentionally reference one object, but a copied node must not accidentally alias the old node’s sockets or payload.
- Inspect the target object’s RED type, not only the matching number.
- Reopen the binary in WolvenKit and verify the nested object is still owned by the intended field.
Let WolvenKit maintain handle identities through normal editor operations. When comparing round trips, compare the resulting object relationships rather than requiring the same incidental numbers.
Diagnose a socket failure
Start with the source and destination nodes and write the intended edge in one line:
node 12 / Out -> node 13 / Active
Then verify:
- the source socket is an output or the node type’s corresponding source role;
- the destination socket is an input with the intended operation semantics;
- spelling and case match the concrete socket contract;
- both socket handles still belong to their intended nodes after round trip;
- the source connection targets the destination socket, not merely the destination node;
- a parallel fan-out is deliberate and does not masquerade as an ordered sequence;
- a
CutDestinationroute is not connected to normal success by accident.
Journal nodes are a common example: entering Active, Succeeded, or
Inactive on the same node can produce three different state changes. A
visible edge is not correct merely because it reaches the right box.
For a child questphase, compare both sides of its public interface:
parent phase-node input In1 -> child questInputNodeDefinition In1
child questOutputNodeDefinition Out1 -> parent phase-node output Out1
The parent can resolve the child resource and still stall if the socket names or terminating output contract do not match.
Diagnose a resource-reference failure
An internal handle can be valid while the object it owns contains a missing external path. Trace the external edge separately:
- copy the exact
ResourcePathfrom WolvenKit; - identify whether the reference is hard, soft, or reached through a registered map/block;
- list the archive and confirm the target path exists;
- inspect any intermediary owner, such as a subtitle map’s entries path or a streaming block descriptor’s sector path;
- check ArchiveXL logs for registration/merge errors;
- confirm the target resource’s root type is compatible with the referring property.
Do not repair a missing ResourcePath by changing a HandleRefId; the handle
may correctly point at the soft-reference object whose path is wrong.
Address indexed resource tables
Some scene fields select a row in a resource table. The actor’s index and the table cardinality form one contract:
maximum referenced index < number of addressable cooked rows
Duplicate source rows do not guarantee duplicate runtime rows. If two entries
resolve to one cooked import while an actor requests index 1, conversion can
succeed and runtime can still perform an out-of-range lookup. Inspect the
round-tripped resource-reference array and every consumer index. The dedicated
Actors, scenes, and lipsync guide applies this to
lipsync slots.
Minimal repair loop
| Failure | Smallest safe correction |
|---|---|
| Dangling handle | Recreate the referenced nested object through WolvenKit and reselect it from the owning property |
| Wrong shared ownership | Duplicate through an editor operation that creates an independent object, then rewire its fields |
| Missing graph edge | Connect the exact named source and destination sockets |
| Wrong operation socket | Reconnect to the intended semantic input, such as Succeeded rather than Active |
| Missing external path | Correct the ResourcePath or pack/register its target; do not alter internal handles |
| Indexed table too short | Supply addressable distinct resources or reduce consumers only as an explicit diagnostic |
Round-trip after each correction. If several edges are repaired at once, a passing result cannot identify which defect caused the original symptom.
Previous: Registration and depot paths. Next: NodeRefs, streaming, and placement.