Troubleshooting
Common issues organized by symptom. Each entry lists the symptom, likely cause, and fix.
Awareness / Perception
| Symptom | Cause | Fix |
|---|---|---|
| No candidates detected at all | Sampler trace channel doesn't match the actor's collision channel | Set the actor's collision object type to one that responds to your sampler's TraceChannel (e.g., Visibility or a custom channel) |
| Candidate detected but wrong actor wins | Scorer weights or ResolverPolicy are misconfigured | Check that ResolverPolicy matches your intent (LowestScore = closest wins with DistanceScorer) and adjust Weight values on each scorer |
| Candidate flickers between two actors | StickyBias is too low for closely-spaced candidates | Increase StickyBias on the FERPChannelPipeline (e.g., 0.2 or higher) to add hysteresis |
| Candidate lost when looking away | A ConeFilter or LineOfSightFilter is too restrictive | Widen the ConeFilter angle or remove filters that are too aggressive for your use case |
| Candidate never updates | PerceptionTickInterval is set very high or bEvaluateOnlyForLocalController is true on a dedicated server | Lower the tick interval; on dedicated servers, set bEvaluateOnlyForLocalController to false if server-side perception is needed |
| OnChannelCandidateAcquired never fires | No pipeline is configured for the channel, or the ChannelId is misspelled | Verify that ChannelPipelines on ERPAwarenessComponent has an entry whose ChannelId exactly matches your domain component's ChannelId |
Interaction
| Symptom | Cause | Fix |
|---|---|---|
| No interaction prompt appears | The interactable actor doesn't pass pipeline filters | Ensure the actor has collision on the correct trace channel, and that ERPInteractableFilter is in the pipeline's Filters array |
| Prompt appears but pressing the key does nothing | The Actions array in the descriptor is empty | Add at least one FERPInteractionAction with a valid InputAction to DefaultDescriptor.Actions |
| Prompt appears, key is pressed, still nothing | The InputAction passed to StartInteractionAttempt doesn't match any action in the descriptor | Use the exact same UInputAction asset in both the descriptor and your input binding |
| "Too far" failure in Output Log | Server-side distance check rejected the interaction | Increase MaxInteractionDistance on ERPInteractionComponent, or ensure the player is close enough |
| "Execution failed" in Output Log | CanBeInteractedWith returned false, or an interaction Rule failed | Check your CanInteractCheck delegate and all Rules on the interaction component |
| Interaction works once then stops | Actor state changed after the first interaction, making CanBeInteractedWith return false | Verify your interactable doesn't inadvertently block re-interaction after the first use |
| Challenge (hold/mash) never completes | StopInteractionAttempt is called immediately (input binding fires Completed on the same frame) | Bind StartInteractionAttempt to the Started trigger and StopInteractionAttempt to Completed (not Triggered) |
| Hold challenge resets mid-hold | StopInteractionAttempt fires when the key is still physically held | Check that your Enhanced Input action has the correct trigger (Hold trigger on the IA itself can conflict; use a simple Press trigger and let the challenge handle timing) |
| Wheel doesn't open | MultiActionMode is set to DirectKeys instead of Wheel | Set DefaultDescriptor.MultiActionMode to Wheel |
| Wheel opens but selecting does nothing | SubmitWheelSelection is called with the wrong UInputAction | Pass the InputAction from the selected FERPInteractionAction, not a different asset |
Targeting
| Symptom | Cause | Fix |
|---|---|---|
| No lock-on / no soft target | No targeting pipeline configured, or the target actor doesn't implement IERPTargetable | Add a pipeline with ChannelId matching ERPTargetingComponent.ChannelId, and ensure the target passes ERPTargetableFilter |
| Wrong target selected | Scorer combination favors the wrong candidate | Tune scorer weights; add a ConeScorer or ViewportEllipseScorer to prefer on-screen targets |
| Target sticks too long when looking away | StickyBias is too high | Lower StickyBias on the targeting pipeline (0.0 disables hysteresis entirely) |
| Lock-on snaps to a dead enemy | CanBeTargetedBy still returns true on death | Return false from CanBeTargetedBy when the target is dead or despawning |
| Reticle widget doesn't appear on the target | ERPTargetableComponent is missing or the widget class is not set | Add ERPTargetableComponent to the target actor and assign a ReticleWidgetClass |
Instanced Interaction
| Symptom | Cause | Fix |
|---|---|---|
| No proxy actor spawns near ISMC instances | MeshConfigTable is null or the mesh in the DataTable doesn't match the ISMC mesh | Assign the DataTable to ERPInstancedInteractionComponent.MeshConfigTable and verify the Mesh soft reference matches exactly |
| Proxy spawns but has no visible mesh | The current state step has Mesh set to null | Set a valid UStaticMesh on the active FERPInstanceStateStep.Mesh |
| Proxy spawns at the wrong location | The ISMC instance transform includes an unexpected component-space offset | Verify the ISMC component's own transform; the proxy uses the instance's world transform |
| State doesn't persist after leaving and returning | ERPInstanceSwapSubsystem state was purged or never written | Ensure the proxy calls SetInstanceState on the subsystem; check that PurgeStaleStates isn't clearing it too aggressively |
| ISMC instance reappears after proxy despawns | The distant stand-in mesh is not configured | Set FERPInstanceStateStep.DistantMesh to the mesh that should remain visible at distance |
| Proxy is interactable in a state where it shouldn't be | The state step has actions in its descriptor | Clear the Actions array in the FERPInstanceStateStep.Descriptor for non-interactable states |
Widgets
| Symptom | Cause | Fix |
|---|---|---|
| Widget doesn't show when looking at interactable | SingleActionWidgetClass (or the relevant widget class) is not set on ERPInteractableComponent | Assign a widget Blueprint class to the appropriate slot (SingleActionWidgetClass, MultiActionWidgetClass, etc.) |
| Widget shows but displays "?" instead of the key | The InputAction on the action doesn't have a key binding in the current InputMappingContext | Add the InputAction to your InputMappingContext with a key mapping |
| Widget doesn't hide when walking away | The widget's OnFocusChanged is overridden but doesn't call the parent or toggle visibility | Ensure your override calls Super or manually sets visibility to Collapsed when bFocused is false |
| Widget appears at the actor's feet | WidgetOffset is (0,0,0) and no ERP_WidgetAnchor tagged component exists | Set WidgetOffset to something like (0, 0, 150) or add a SceneComponent with tag ERP_WidgetAnchor |
| Widget shows stale data after the actor changes state | The descriptor changed but the widget wasn't notified | Call ForceRefreshDescriptor() on the interaction component after changing the interactable's state |
| Challenge sub-widget doesn't update progress | OnActionProgress in your interaction widget doesn't forward to the challenge sub-widget | Override OnActionProgress and call SetChallengeProgress(Progress) on the matching UERPChallengeWidgetBase |
Performance
| Symptom | Cause | Fix |
|---|---|---|
| High tick cost from perception | PerceptionTickInterval is 0 (every frame) with many candidates | Increase PerceptionTickInterval (e.g., 0.1 = 10 Hz) to reduce evaluation frequency |
| Sphere overlap is expensive | Sampling range is very large (e.g., 5000+) in a dense world | Reduce DefaultSamplingRange to the minimum needed; use separate channels with different ranges for interaction (short) vs. targeting (long) |
| Too many candidates scored each tick | No filters are configured, so every overlapped actor goes through scoring | Add filters (ERPDistanceFilter, ERPConeFilter, ERPLineOfSightFilter) before scorers to cull early |
| Instanced interaction causes hitches | Many proxies spawning/despawning simultaneously | Increase ScanInterval on ERPInstancedInteractionComponent and reduce SwapRadius to limit concurrent proxies |
| Widget components cause draw call spikes | Many world-space widgets rendering simultaneously | Use AmbientWidgetClass sparingly; consider screen-space HUD widgets driven from OnDomainCandidateChanged instead |
General Tips
- Enable debug logging: Set
bDebugPerception = trueonERPAwarenessComponentto see candidate evaluation in the Output Log. Filter byLogElysAwareness. - Check channel IDs: The most common silent failure is a
ChannelIdmismatch between the pipeline and the domain component. They must match exactly (case-sensitive). - Verify collision setup: Perception samplers use physics traces. If an actor has no collision or is on the wrong channel, it will never be detected.
- Test in standalone first: Multiplayer adds server-side validation. Get interactions working in standalone PIE before testing client-server.