The attack logic is being called, but the enemy's HP does not drop from 100. Even when Print String tells you "the damage passed was 0," it may not show you which calculation produced that 0.
That is what the Blueprint Debugger is for. It pauses just before the suspect logic so you can advance a little at a time and check values. It is the tool for investigating "why did it become that value" after the log has told you "what happened."
In this article we build a small example that deliberately sets the damage multiplier to 0. We follow it together through stop → inspect values → fix the setting → confirm HP drops from 100 to 80.
What You'll Learn
- How to stop just before a node runs with a breakpoint
- How to choose your inspection scope with Step Into, Over, and Out
- Why you distinguish "not yet run" when reading pin values and Watches
- How to choose which instance of the same Blueprint to observe with Debug Object
Use logs and the Debugger according to what you want to know

| What you want to know | The easier tool |
|---|---|
| Whether the attack logic ran, and how many times | Print String and the Output Log |
| Which value was used and which branch was taken | Blueprint Debugger |
| Observing mashing or timing intervals while it runs | Logs or recording tools |
Both let you inspect values. The Debugger lets you check pins and variables without adding a Print each time, and logs let you record progress without stopping the game. You can also narrow down the suspect area with the Print String article and pause where you want detail.
Timing-dependent bugs can change conditions when you pause or shift focus to the editor. If it stops reproducing when you pause, go back to taking logs while it runs.
A breakpoint marks "stop just before running"
A breakpoint marks "when execution reaches this node, stop before running it." Put them on Sets, Branches, and function calls with white exec lines.
- Right-click the node you want to stop at and choose "Add Breakpoint." The default shortcut is
F9. - Compile, save, and Play. Playing inside the editor like this is called PIE (Play In Editor).
- Perform the action that calls that logic. On arrival it pauses and highlights the node.
The important part is that the node you stopped at is about to run. If you stopped at Set Health, that Set has not rewritten HP yet.

Pure nodes with no white exec line, such as an addition or a variable Get, are computed when the side using the value needs them. Rather than trying to put a mark there, stop at the Set that uses the result or at the function call that computes it.
Mark states and how to open the Debugger
An enabled mark is filled red; a disabled one is just an outline. A yellow "!" means it cannot validly stop there. Compiling sometimes clears it; if not, hover the mark to see the reason.
To see the list and Watches, open "Blueprint Debugger" from Tools in the main editor. You can also open it from the Blueprint editor's Debug menu. Breakpoints work even without opening the dedicated window.
Stepping: in, over, and out
While paused, the toolbar's step operations advance execution. Learning the name of each operation lets you use them in environments with different key bindings.

| Operation | What happens | When to use it |
|---|---|---|
| Step Into | Advances and enters a Blueprint function | You want to inspect the calculation |
| Step Over | Runs the current logic and continues without tracing inside a function | You only need that function's result |
| Step Out | Runs the rest of the current function and returns to the caller | You are done inspecting inside |
| Resume | Returns to normal execution | You want the game to continue |
Both Over and Out run the logic. They do not rewind or undo a function's effects. You may also stop again at another breakpoint along the way.
Assignments such as F10 and F11 can be checked in "Editor Preferences" → "Keyboard Shortcuts" by searching Step Over / Step Into. The hands-on below is fine to work through with the toolbar buttons.
The debugger cannot rewind, so if you miss something, place a breakpoint earlier and repeat the same action. Choosing your scope — Into only the suspect functions and Over the confirmed ones — makes it easier to follow.
Reading values: hovering pins and Watch
While paused, hover a data pin to check its value. But what is shown is the value from the last time that node ran. The output of a node that has not run yet does not hold this pass's result.
For example, when you stop just before calling the damage calculation, the result does not exist yet. Seeing "cannot display value" there does not mean the damage is 0. Run the logic you need, then look again.

Watch is a feature that registers pins you want to check repeatedly into a list. Right-click a pin name and choose "Watch this value" to follow it in the Debugger. This too cannot show values that have not run.
We use this distinction in the hands-on next. We store the calculation result in a variable inside the function and, once that runs, inspect the two values that were multiplied.
Debug Object: which instance to observe
Place three of the same BP_Enemy and each of the three holds its own HP. An actual object created from the Blueprint plan like this is called an instance.

The Blueprint editor's Debug Object is the field for choosing what to observe. To start, restricting the target to one instance as in the hands-on avoids mixing up values from a different instance.
With several instances, press Shift + F1 during Play to return the mouse to the editor and choose the running instance you want from Debug Object. Use the Actor name you set in the level as your clue. Settings or run state can also cause a target to be selected, so rather than assuming "nothing was selected," confirm the current name.
Choosing a target does not send the attack to that Actor. What matters is aligning the object your game logic acts on with the object you observe in the Debugger.
Hands-On: investigating why damage becomes 0
Pressing F sends one round of damage logic to a practice enemy. At first the multiplier is 0, so HP does not drop. We confirm that 0 in the Debugger, then fix the multiplier to 1.

Create a UE5 Third Person template in Blueprint, choosing None if there is a Variant option. Work in a new practice folder. We prepare no attack animation or collision, so the same conditions can be repeated with a key press.
1. Prepare the practice enemy and variables
Create BP_DebugDamageEnemy with Actor as parent. Add a Static Mesh under DefaultSceneRoot, set the standard Cube, and set relative location and rotation to 0 with Scale 1. Cube can be selected from Engine/BasicShapes with "Show Engine Content" on. Set Collision Presets to NoCollision and turn off Simulate Physics.
Create the following variables, Compile, and set defaults. Leave Instance Editable off.
| Variable | Type | Default | Meaning |
|---|---|---|---|
| Health | Float | 100 | The current HP |
| BaseDamage | Float | 20 | Damage before the multiplier |
| DamageMultiplier | Float | 0 | The damage multiplier. Our deliberate bug |
A multiplier represents how many times the original amount to apply. 1 keeps 20 damage, 0.5 makes it 10, and 0 makes it 0. Here we investigate a settings mistake: "it should be 1 for a normal attack, but it was 0."
2. Create the calculating Function
Create Function CalcPracticeDamage with Pure off so it can be called on a white exec line. Add Damage to Outputs as a Float. Under the function's Local Variables, create CalculatedDamage as a Float with default 0.
CalculatedDamage is a temporary variable belonging only to this function where the result is parked once. We place that intermediate Set so we can stop before and after the value is stored.
- Connect the function entry's white line to Set CalculatedDamage.
- Place a Float multiply
*and pass Get BaseDamage to A and Get DamageMultiplier to B. - Pass the multiply result to Set CalculatedDamage's value.
- Connect the Set's white output to the Return Node and pass Get CalculatedDamage to Return's Damage.
The Return Node is the exit that hands the computed value back to the caller. Call this function and you receive the result from the Damage output.

3. Reduce HP with the returned result
Create a Custom Event ApplyPracticeHit in the Event Graph. From this event, call your CalcPracticeDamage and connect Set Health after it.
The value fed into Set Health is a Float subtraction of Get Health − CalcPracticeDamage's Damage output. Pass that through Max (Float) with the other input set to 0 so HP never goes below 0.

The "from" and "to" in the diagrams are pointers showing how it connects to the diagrams before and after. You do not add nodes with those names.
Place a Print String after Set Health. Pass Health: to Append's A and Get Health converted with To String (Float) to B, then connect the Return Value to Print String's In String. Set Duration to 10 seconds.
To String turns the number into text and Append prefixes it with Health: . What the Print reads is Health after the Set. That lets you confirm on screen "what HP became as a result of calling it." We add no logic to destroy the enemy at 0 HP.

4. Make F call the same logic
Compile, save, and place one BP_DebugDamageEnemy in front of the Player Start. Set the Actor's Scale to 1 with its center about 50 cm above the floor. Renaming it to DebugEnemy in the Outliner makes it easier to find later.
- With the placed DebugEnemy selected, open "Open Level Blueprint" from the level's Blueprint menu.
- Right-click in the graph and create "Create a Reference to DebugEnemy" for the selected Actor.
- From that reference, create a node calling ApplyPracticeHit.
- Place a keyboard F event and connect Pressed to ApplyPracticeHit's white input. Target is the placed DebugEnemy reference.

Compile, save, Play, click the game view, and press F once. Seeing Health: 100 means you reproduced the deliberate bug. Get this far, then stop Play.
5. Stop on the calling side and step into the function
Go back to BP_DebugDamageEnemy and put a breakpoint on the CalcPracticeDamage call node in the Event Graph. Right-click the node connected by the white line, not the name in the Functions list.

Start a new Play and press F once in the game view. When it stops at CalcPracticeDamage, confirm Debug Object points at the running DebugEnemy instance.
At this point this pass's Damage output has not been computed. Use Step Into to enter the function and follow along until Set CalculatedDamage runs. If you stop just before the Set, use Step Over to run it.
Gets and the multiply are evaluated when preparing the value passed to the Set. You do not step through every small node on screen one by one.
6. Confirm the values used in the calculation
Once Set CalculatedDamage has run and you advance to the Return Node, hover the output pins of Get BaseDamage and Get DamageMultiplier feeding the multiply.
| Value to read | The result we want to confirm |
|---|---|
| BaseDamage's output | 20 |
| DamageMultiplier's output | 0 |
| The multiply result | 0 |
The original damage of 20 is correct, and since the multiplier is 0, the product is 0 too. You learn that the calculation node is not broken — the setting fed into the calculation is wrong.
Here, right-click DamageMultiplier's output pin and choose "Watch this value." Check the value in the Blueprint Debugger so you can compare the same pin on the next attempt.
If you overshot the spot you wanted, put a breakpoint on the Return Node too, restart Play, and press F. Resuming from the calling side stops you just before Return with the Set already done. If no value appears, confirm whether the node has run and whether the target instance matches.
7. Fix the multiplier and repeat the same action
Stop Play. Change BP_DebugDamageEnemy's DamageMultiplier default to 1, then Compile and save. Do not stop at changing only a temporary in-game value.
Start a new Play and press F once. Stepping into the function the same way, this time BaseDamage is 20, DamageMultiplier is 1, and the multiply result is 20. Confirm in the Watch too that the evaluated multiplier is now 1.
Resume, and if you stop at other breakpoints, continue again. Seeing Health: 80 means the corrected calculation reached HP.
Try 0.5 as well: pressing F once in a new Play gives 10 damage and Health: 90. Afterwards, set the multiplier back to 1 and delete or disable the breakpoints you no longer need.
Restarting Play each time is to reset Health to 100 for comparison. Press F repeatedly within the same Play and the next damage applies to the already-reduced HP.
When it doesn't stop, or values don't appear
| Symptom | Where to check |
|---|---|
| Pressing F does nothing | Whether input is going to the game view, the level's F Pressed and Target on the placed Actor |
| Print appears but it doesn't stop | The breakpoint's enabled state, Compile, the current Debug Object |
| A yellow "!" appears | The mark's hover explanation. Whether it is on an exec node rather than a pure node |
| No value shows on a pin | Whether the logic using that Get or calculation has already run this pass |
| Multiplier changed to 1 but still 0 | Whether you stopped Play and edited the default, whether you compiled and saved, whether you are looking at a different instance |
Bonus: Good to Know Up Front
Use the Call Stack to see where you were called from
The Call Stack is the history of "which function led into the current one." The function currently running sits at the top. It helps when several similar entry points exist and you are unsure which one called you.
Execution Trace, meanwhile, is a list of recently executed nodes. Look here when you want to follow the nodes you passed through. Open the panels you need in the Blueprint Debugger and confirm rather than relying on the glow of exec lines alone.
Stop where Accessed None happens
Accessed None is the error you get when using a reference that points at nothing. Search "Editor Preferences" for Blueprint Break on Exceptions and enable it to stop where such exceptions occur. It is under Experimental's Blueprints.
Since it stops more often, use it while investigating reference problems. To inspect inside a Component, also confirm the Component instance owned by that Actor in Debug Object (the Component article).
Preserve the fixed conditions in an automated test
Here you could preserve "BaseDamage 20 with multiplier 1 returns 20" and "20 damage on HP 100 gives 80." The automated testing article covers how to verify expected results like these in Blueprint.
With a test in place, you notice when the same bug comes back under the same conditions. You can connect the roles: investigate the cause with the Debugger, and confirm repeatedly with the test.
Summary
In the Blueprint Debugger, you stop just before suspect logic and inspect values while advancing only the range you need.
- The node you stopped at with a breakpoint is about to run.
- Into enters, Over runs without tracing inside, and Out finishes the current function.
- Pins and Watches show the most recent executed value. Do not mistake "not yet run" for 0.
- Use Debug Object to align the object your game acts on with the one you observe.
- If you miss it, stop earlier and, after fixing, try again under the same conditions.
In the damage example we changed 20 × 0 to 20 × 1 and confirmed HP 100 → 80 at the end. Tracing back from a result to the ingredients that produced it is what gives you a lead on the cause.
If the graph is hard to follow, see 10 techniques for organizing; if you would rather search by common failures, see 10 Blueprint mistakes.