Debugging & Troubleshooting

Documentation Unreal Engine AI FAQ

The symptom you are looking at, the one thing that causes it, and the fix.


Find what you are seeing in the list below, read the cause, apply the fix.
Most reports of "nothing happens" come down to one thing: the enemy has no combat target. Movement, action scoring and the combat phase all read the controller's focus actor, and nothing sets that until a target is registered and the enemy is aware of it. Start with The enemy stands there and does nothing.

Debug it

Press Play and turn the overlays on. Each writes a block above the pawn it belongs to.
SEC.Debug.Role 1        // Name and combat role, coloured by role
SEC.Debug.Decision 1    // Distance, angle, line of sight, speed, threat
SEC.Debug.Scoring 1     // What each action scored, highest first
SEC.Debug.Movement 1    // Movement layer, strafe side, heading
SEC.Debug.Awareness 1   // Awareness state, meter, age of the last known location
SEC.Debug.All 1 turns every block on at once. SEC.Debug.WatchPawn <name> narrows them to one enemy (part of a name is enough, and the console names which pawn it picked), and SEC.Debug.WatchClear puts them all back.
Twelve sections exist: Role, Decision, Movement, Awareness, Territory, Actions, Reactions, Scoring, Tokens, Vitals, Teams and Approach. Each takes 1 or 0.
For a record you can scroll back through, switch the logs on instead.
Console variablePrints
SEC.Debug.LogActionDecisionsWhy each action scored what it did, and what refused the rest
SEC.Debug.LogActionExecutionAction starts, ends and cooldowns
SEC.Debug.LogReactionsWhich trigger rule answered an event, and with what
SEC.Debug.LogRoleAssignmentsRole assignment (2 for verbose)
SEC.Debug.Movement.LogMovementLayer switches, pathfinding, stuck, detour
SEC.Debug.Threat.LogThreat events
The world drawings cover what you need to see in the level rather than read.
Console variableDraws
SEC.Debug.Movement.DrawScoringThe sampled directions, red low to green high
SEC.Debug.Movement.DrawNavNavmesh validity and the ledge guard
SEC.Debug.Movement.DrawAvoidanceAvoidance radii and the pawns being avoided
SEC.Debug.Melee.DrawTracingThe swept shapes of a weapon trace
SEC.Debug.Stimulus.DrawAttack telegraphs going out
SEC.Debug.Steering.DrawMotion warps and approach windows
SEC.Debug.Threat.DrawThreat cone, progress arc, colour grading
Decision, Movement, Scoring, Awareness, Territory, Tokens and Approach are worked out on the server and draw only there. Role, Actions, Reactions, Vitals and Teams replicate, so they read on a client too.
AdvancedDebug one enemy from the Details panel
Each of the twelve overlay sections has a Debug Overlay checkbox on the component it reads from, and ticking one there affects that enemy alone. The movement, action, threat and reaction logs and world drawings sit beside them as checkboxes too. The remaining console switches are global only.
Details
Action Evaluation Component
Debug
Debug Log Decisions
Debug Log Execution
Component flags OR matching SEC.Debug.* console variables enable the same logs.
Details
Movement Evaluator Component
Debug | Draw
Debug Draw Scoring
Debug Draw Avoidance
Debug Draw Nav
Debug | Log
Debug Log Movement
Debug Log Tick
Debug Log Scoring
Debug Log Avoidance
Debug Log Strafe Swap
Debug Log Strafe State
Component flags OR matching SEC.Debug.Movement.* console variables enable the same output.
They are readable and writable from Blueprint, so a debug menu can drive them at runtime.
SEC.Debug.ScoringRows sets how many rows the score list keeps, 5 by default and 0 for all of them. SEC.Debug.MaxDistance (4000 cm) sets how far from the camera a block still draws, and SEC.Debug.TextScale sizes the text.
The per-tick movement stream writes to its own log category, so you can mute it while one enemy floods the console:
Log LogMovementEvaluatorTick off

Nothing happens

The enemy stands there and does nothing

No combat target, or the enemy never reached its combat phase. Check these five in order.
  1. AI Controller Class is unset on the pawn Blueprint. The pawn gets the project's default controller and none of the combat components exist. Set it in Class Defaults.
  2. Target Selector is empty on the Enemy AI Config. An empty one still takes the first target the enemy may fight, so this rarely leaves a single enemy idle, but it gives you no say in which target it takes. Set it to Awareness Filtered Target Selector and leave its Inner Selector empty, so it offers the nearest target this enemy has perceived. Closest Target Selector works too, though it engages anything registered whether the enemy sensed it or not.
  3. Awareness Config is empty on the Enemy AI Config. The enemy senses nothing, holds at Unknown, and never enters its combat phase. Point it at an Awareness Config asset and leave that asset's defaults alone. This config does the perceiving; the filtered selector in step 2 is what turns perception into aggro, so fill in both.
  4. The player was never registered as a combat target. On the player pawn's Event BeginPlay, branch on Has Authority, then call Register Combat Target on the AICombat Role Subsystem with Target Actor set to Self. See Getting Started.
  5. The AI Config is on neither the pawn nor the controller, so there is nothing to resolve at possession.
SEC.Debug.Role 1 reads None for an enemy that never took a target. No block above the pawn at all means it carries no SEC components, which points at the first cause.

It moves but never attacks

Something refuses every action before it scores.
Run SEC.Debug.Scoring 1. An action a hard gate refused prints the reason in place of a score. The usual reasons:
ReasonFix
Enabled unticked on the actionTick it. Unticking it also stops the ability being granted.
Selection is Manual OnlyThat action waits for a direct Execute Action call. Set Selection to Scored for a scored move.
Selection is Chain OnlyNothing chains into it, or the chain window has closed. Wire a chain into it from another action, or set Selection to Scored.
On cooldown, or Max Consecutive Uses spentExpected. Give the enemy a second action to switch to.
RecoveryThe gap after any action. The three Recovery fields on the AI Config ship at 0, so this holds nothing back until one of them carries a value.
A gate said noA Combat Token Gate on a full pool, or a Stamina Gate under its minimum.
Requires Tags or Block TagsThe enemy, the target or the world does not hold the right tags.
Require Line Of Sight tickedThe view to the target is blocked.
SEC.Action.BlockActionsThat tag sits on the enemy's ability system component. Something added it and never removed it.

It scores and wins, but nothing happens

The action starts something that does nothing.
  • The ability has no activation graph. An ability implementing neither Activate Ability nor Activate Ability From Event starts and never ends.
  • The Montage Payload has no montage. Saving the Action Set reports this in the Asset Check message log.
  • The Action ID is empty. An action added through the Details panel array instead of the canvas has no ID, wins the poll, then gets discarded silently. Opening the asset on its canvas repairs it.
  • Manage Action Sets Automatically is unticked on the AI Config, which applies nothing at all.

A revived or pooled enemy never acts again

Death holds a block on action evaluation, and only a revive releases it.
Call Handle Revive on the SEC Combat Controller component when the enemy comes back. It releases the block, restarts the brain, and turns threat detection, perception and role registration back on. Re-equip the weapon yourself, since death released it.

Attacks

It swings from across the room

The action has no Distance Scorer, so it has no opinion about distance.
Open the Action Set, and on the card's Scoring > Scorers list add a Distance Scorer. Its Range defaults to a melee band peaking between 100 and 250 cm. A brand new action ships with no scorers at all, which is what lets it fire at any range. See Action System.

It attacks once and then freezes

The ability the action started never ends, so the action waits on it.
  • Give the ability a path that reaches End Ability on completion, on cancel and on interrupt. An ability playing a montage through Play Montage and Wait ends when the montage does.
  • Set Ability Timeout on the action's execution method, behind the advanced arrow, to bound the wait.
  • For an ability meant to keep running, pick the Gameplay Ability (Fire And Forget) execution method so the action finishes in the same frame.
A 30 second safety limit forces completion either way and names the action that hit it.

It pauses too long between attacks

Recovery holds offensive actions back after any one of them ends, while movement and reactions keep running.
Tune it on the Enemy AI Config under Recovery.
FieldSets
Action Recovery TimeSeconds held off after an action completes.
Interrupt Recovery TimeSeconds held off after an action is interrupted or cancelled. Keep it shorter than the above.
Action Recovery Time RandomizationJitter on the completion window.
All three at 0 turns recovery off. To override it for one move, tick Override Recovery Time on that action and set Recovery Time, which replaces the global value rather than adding to it. SEC.Debug.LogActionDecisions 1 prints Recovering (X.Xs remaining) while the gate holds.

The whole pack swings at once

The attacks carry no Combat Token Gate, so nothing caps how many enemies act on one target.
Add a Combat Token Gate to each attack, then set the pool size under Combat Tokens in Project Settings. Two token tags ship with a Budget of 2 each. See Combat Tokens.
Two things quietly defeat it. A token tag with no row in Project Settings hands out unlimited slots, and an enemy with no focus target claims nothing and runs uncapped. SEC.Debug.Tokens 1 writes the pool above the head of the target the slots belong to, rather than above an attacker, and prints unlimited in place of a count for the first case.

An attack lands but deals no damage

Read the Output Log first. The trace component names most of these itself.
CheckWhat to look for
Socket IDsThe IDs on the melee trace notify match Trace Sockets on the weapon exactly. A window naming a socket nothing registered says so in the log.
Trace FilterIn Channel mode, the channel the target blocks. In Object Types mode, the type the target belongs to. Turn on SEC.Debug.Melee.DrawTracing 1 and watch the sweep.
Damage ConfigDefault Damage Config on the trace component, or Damage Config on the notify. Damage does not come from the weapon actor class.
The target answers damageIt implements the SEC Damageable interface (reparenting to Enemy Character Base covers this), or handles Event Any Damage, which the sweep falls back to.
A sensor in the wayA component that blocks the trace channel stops the sweep before it reaches the body behind it. Set that component's response to the trace channel to Overlap.

Movement

It does not move at all

Six causes, in the order worth checking.
  • No focus actor. Nothing registered a combat target, so there is nothing to move relative to. This is the common one and it logs nothing.
  • The Movement Evaluator sits on the pawn. It belongs on the AI controller. On a pawn it warns once at BeginPlay and then does nothing.
  • No navmesh. Past 800 cm the enemy asks for a path, the request fails every tick, and it never closes the gap. Add a NavMesh Bounds Volume, build navigation, and press P in the viewport to check it covers the floor. On a large or open world map, see the navmesh is empty on a large map below.
  • A leftover SEC.State.IsMovementBlocked tag on the enemy's ability system component freezes it outright. It ships in a new action's Add Tags and is meant to clear when the action ends.
  • Apply Movement Input is off on the Movement Evaluator, which is evaluate-only mode.
  • The AI Movement task is not running. In a StateTree graph it has to stay in a running state through combat. See StateTree Integration.
The first Play In Editor after opening a project can start before navigation finishes building, and a game world never fills a tile the editor world had not reached. An enemy that pathfinds on the second Play and not the first has hit this. Build > Build Paths and save the map.

The navmesh is empty on a large map

An open world, or any level using Dynamic navmesh generation, builds navigation around invokers rather than everywhere at once. With no invoker in the level nothing asks for a tile, so the navmesh stays empty and every enemy past 800 cm fails its path request. Pressing P shows bare ground.
Add a Navigation Invoker component to the actors navigation should follow, the player pawn first. Each one asks for tiles within its generation radius and lets them go past its removal radius.
Add it to the enemies as well when they wander far from the player, since an enemy outside every invoker's radius stands on unbuilt ground. Set Runtime Generation to Dynamic in Project Settings > Navigation Mesh for invokers to have anything to drive.

It grinds against a wall

The target sits behind cover. The straight-line distance stays short while the walking route is long, so tactical steering pushes into the geometry.
Detour escalation catches this and hands off to pathfinding to round the corner. Check on the Movement Evaluator, under Hybrid Movement > Detour:
  • Enable Detour Escalation is on (it ships on).
  • The navmesh offers a route around the obstacle.
  • Lower Detour Enter Ratio (default 1.6, try 1.4) or Detour Min Excess (default 200 cm) when a real detour still reads as minor.
  • Detour Escalate On Stall is on for tight corners. Raise Detour Stall Speed if a slow grind does not register.
SEC.Debug.Movement.LogMovement 1 prints each recheck as ENGAGE, HOLD or release. See Movement System.

A Waiter or Flanker freezes after the player jumps a gap

The player is close in a straight line while the walkable route wraps around the pit, and a Waiter or Flanker can already be inside its band, so steering idles at the rim with sight clear across the gap.
  • Leave Detour Use Line Of Sight Pre Gate on. It reads the navmesh along the straight line, so a gap engages the detour even with sight clear.
  • Check both sides of the gap sit on connected navmesh. A route that stops at the rim means no walkable way across, and staying tactical is the right answer.
  • Lower Detour Release Ratio (default 1.35) only if the enemy gives up the route too early on a short way around.
SEC.Debug.Movement.LogMovement 1 prints Detour eval: skip (no reachable route) when the far side is not connected.

It jogs instead of running while closing in

Sideways movement costs speed, and direction scoring angles the approach a few degrees while the enemy holds a strafe side or steps around a neighbour.
Raise Strafe Free Angle on the Movement Evaluator (15 degrees), the band around straight ahead that costs nothing. Strafe Speed Penalty (0.75) softens the cost everywhere including real circling, and 0 turns it off. Check the run window in your locomotion graph too, since a 30 degree approach keeps most of its speed by design. See Movement System.

It walks off a ledge or into a hazard

The navmesh ends past the visual drop, or the hazard is painted as cost rather than as an area to avoid.
  • Press P and check where the navmesh stops.
  • Enable Nav Aware Sampling is on and Nav Score Weight is above 0.
  • For a patch the enemy can walk on but should not, add the nav area to Hazard Area Avoidance on the Movement Evaluator with a strength around 0.75, where 0 ignores it and 1 scores it like a wall. High nav cost alone still reads as walkable at close range.
  • Tune Nav Probe Distance (120 cm): lower in tight spaces, higher for fast movers.
SEC.Debug.Movement.DrawNav 1 marks blocked directions with blue spheres. See Movement System.

It walks home in the middle of a fight

Its territory leash broke, or it refuses a target standing outside the leash.
On the pawn's SEC Territory component, under Leash:
  • Leash Enabled ships off. Something turned it on.
  • Leash Radius (2000 cm) is measured straight from the anchor, so a radius tighter than the wander area reads as broken while the enemy drifts.
  • Only Fight Inside Leash is on by default, so a target beyond the ring is ignored outright. Untick it for an enemy that charges anything it notices and gets dragged home instead.
  • Leash Break Grace Time (2 s) is how long it may stay out before it gives up. 0 turns for home the moment the line is crossed.
SEC.Debug.Territory 1 draws the boundary and prints how far the leash is from breaking. See Territory.

Reactions and animation

It never parries or dodges

Nothing announced the attack, so no trigger rule ever ran.
  1. Put a SEC Attack Telegraph notify over the windup in the attacker's montage. Without it no stimulus goes out and the enemy stands there taking hits.
  2. Give the Reaction Set a Trigger Rule whose On Stimulus matches the event, wired to at least one reaction.
  3. Check the enemy has a Reaction Set at all, through Default Reaction Set on the AI Config.
SEC.Debug.Stimulus.Draw 1 shows whether anything is going out. SEC.Debug.LogReactions 1 names the rule that answered, or prints answered by nothing with the rule count it walked. See Reaction System.

A behavior tree action starts nothing

The blackboard has no key for the action's payload, so the tree receives nothing to act on. A write to a missing key is dropped by the engine, and the log names the key once per blackboard.
Add these keys to the blackboard asset:
KeyTypeBase Class
SEC_PayloadObjectExecution Payload
SEC_ActionIdName
SEC_TargetActorObject
SEC_SelfActorObject
SEC_DistanceFloat
Then point Payload Key Name on the action's execution method at SEC_Payload. BB_SEC_Basic in the showcase content declares SEC_Payload, SEC_ActionId, SEC_TargetActor and SEC_Distance already, so build on it or copy it.

Hits pass through on a dedicated server

The character's mesh is not refreshing its bones on that machine, so the sweep reads a stale pose.
Set the mesh's Visibility Based Anim Tick Option to Always Tick Pose And Refresh Bones. The trace component reports this once per character in the Output Log. Enemy Character Base handles it for you.

Packaging

A packaged build fails with "Missing Dependency GameplayAbilities"

Unreal does not stage an engine plugin your project depends on only through another plugin.
Open your .uproject and add "SupportedTargetPlatforms": ["Win64"] to each engine plugin entry it lists, matching the platforms you ship. The alternative is a DirectoriesToAlwaysStageAsNonUFS entry per plugin in DefaultGame.ini.

FAQ

Can I use this with a character I already have?
Reparent it rather than rebuilding it. File > Reparent Blueprint, then pick Enemy Character Base for the pawn and Enemy Controller Base for the controller. Your existing components, variables and graphs stay, and you inherit the ability system, the combat components and the damage interfaces. Delete any duplicate the Blueprint added itself, such as its own ability system component.
Adding the components to a bare AI controller is not equivalent. The base controller holds the AI's facing during an attack and turns it toward a target's last-known location, and attack abilities rely on that.
Does this work in multiplayer?
Yes, on a listen server and on a dedicated server. AI decisions run on the server. Vitals, action and reaction execution state, combat roles and the active sets replicate to clients. See Multiplayer.
How much of this needs GAS?
Melee traces and the damage path resolve without an ability system on either actor: a target that implements the damage interface answers directly, and anything else falls back to engine point damage. Running actions and reactions through the Gameplay Ability execution methods needs one, since that is where blocking tags, cooldowns and the end-of-ability signal come from. The plugin lists GameplayAbilities as a dependency either way.
How do I handle death: ragdoll, weapon drop, dissolve?
Call Handle Death on the SEC Combat Controller component. It stops the brain, cancels the running action and reaction, stops melee tracing, disables threat detection, unregisters the enemy from the role system, clears focus, and fires On Death. The pawn is then safe for ragdoll, dissolve or destroy; none of that happens on its own.
Drop Weapon On Death is on by default and releases everything the pawn holds with Drop, which asks each item to drop itself. Untick it to release with Leave In World instead, which detaches each item and leaves it standing where it was.
Auto Handle Death On Health Depleted is on by default, so an emptied health vital runs the shutdown without a call from you.
Which engine versions, and does source ship?
Version 3.0.0 runs on Unreal Engine 5.6, 5.7 and 5.8. Full C++ source ships with the plugin.

Support

Purchase and updates: Fab
Questions, bugs and feature requests: Discord, or the Fab product page.