Quick answer: Both actors must have Generate Overlap Events enabled on their Primitive Component, the collision profile must resolve to Overlap (not Block or Ignore) for the relevant object type pair on both sides, and the actor’s mobility must not be set to Static.

Overlap events in Unreal Engine look deceptively simple on the surface — drop a collision box, bind the event, ship the feature. Then playtest day arrives and your pickup item sits on the floor doing absolutely nothing as your character walks straight through it. The event never fires. No error in the output log, no warning, just silence. This is one of the most frequently reported Unreal bugs in game-specific support channels, and it almost always comes down to a checklist of settings that must all be true simultaneously on both actors involved.

The Root Cause: Every Setting Must Be True on Both Sides

Unreal’s overlap system is bilateral. For OnComponentBeginOverlap to fire, the engine must determine that an overlap occurred and that both participants have opted in to receiving overlap notifications. If either actor is missing even one required setting, the entire event chain is silently suppressed. There is no log warning. There is no fallback. The event simply does not happen.

The relevant settings are spread across three different places in the editor: the component details panel, the collision profile, and the actor’s Transform/Mobility section. Missing any one of them is enough to break the whole chain.

Step 1: Enable “Generate Overlap Events” on Both Primitive Components

Select each actor in the viewport, open its Details panel, and find the Primitive Component responsible for collision — typically a UStaticMeshComponent, UCapsuleComponent, or UBoxComponent. Under the Collision section, confirm that Generate Overlap Events is checked. This must be true on both the triggering actor and the actor being overlapped.

In C++, you set this per component in the constructor:

// In your actor's constructor
UBoxComponent* OverlapBox = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapBox"));
OverlapBox->SetGenerateOverlapEvents(true);
OverlapBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);

ECollisionEnabled::QueryOnly is correct for overlap-only volumes. QueryAndPhysics also works but adds unnecessary physics cost. PhysicsOnly or NoCollision will prevent overlaps entirely regardless of any other setting.

Step 2: Verify the Collision Profile Resolves to Overlap for Both Object Types

Even with Generate Overlap Events checked, the collision channel response must actually be set to Overlap (not Block or Ignore) for the object types involved. Open the Collision section of the component details and click Collision Presets → Custom. Check the response for the object type of the other actor.

A common trap: your character uses the "Pawn" preset and your pickup uses "OverlapAll", but somewhere along the line someone changed the pickup’s response to Pawn from Overlap to Block. Now the physics system resolves to a block, and overlaps are suppressed because a block takes precedence.

From C++, you can set the response explicitly:

OverlapBox->SetCollisionResponseToAllChannels(ECR_Ignore);
OverlapBox->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
OverlapBox->SetCollisionObjectType(ECC_WorldDynamic);

The engine resolves to the minimum response between the two actors. If Actor A says Overlap and Actor B says Block, the result is Block — and no overlap event fires. Both must agree on Overlap.

Step 3: Check Actor Mobility — Static Actors Do Not Generate Overlaps

This is the most surprising gotcha for developers coming from other engines. In Unreal, any actor with its root component Mobility set to Static will not generate overlap events at runtime, full stop. The engine treats static geometry as immovable world geometry and skips overlap processing for it to save CPU time during broad-phase culling.

If your pickup, trigger zone, or interactable prop has mobility set to Static, set it to Movable (or at minimum Stationary). You can verify this in the Details panel under Transform. If the actor’s blueprint has a Static Mesh as the root component and you never changed the mobility, it may have defaulted to Static.

Step 4: Understand OnComponentBeginOverlap vs OnActorBeginOverlap

The actor-level event OnActorBeginOverlap is a delegate that fires on the AActor class after the component-level event fires on the overlapping UPrimitiveComponent. They are not independent. If the component event never fires (because of any of the above settings), the actor event will never fire either.

In Blueprint this is easy to confuse because both events look similar in the Event Graph. In C++, make sure you are binding to the right delegate:

// Component-level (preferred — bind in BeginPlay)
OverlapBox->OnComponentBeginOverlap.AddDynamic(
  this, &AMyActor::OnOverlapBegin
);

// Actor-level (fires after component event)
OnActorBeginOverlap.AddDynamic(
  this, &AMyActor::OnActorOverlap
);

The function signatures differ. OnComponentBeginOverlap passes the overlapping component, the other actor, the other component, and sweep result data. OnActorBeginOverlap passes only the two actors. Mismatching the signature will cause a silent binding failure at runtime in Debug builds and a crash in Shipping.

Step 5: Use the Collision Visualizer to Debug Channel Settings

When you’ve checked all the above and the overlap still isn’t firing, open the editor and use the built-in Collision Visualizer. In the viewport, click Show → Collision to render collision geometry, or use the console command show Collision in PIE. Then enable the Collision Channel Debugger via p.VisualizeCollision 1 in the output console while playing.

More useful for channel debugging is the Developer Tools → Collision Analyzer window. Open it during PIE and filter by your actor’s name. It shows every query frame, the channels involved, and the response results — you can see at a glance if your overlap query is resolving to Block or Ignore instead of Overlap.

Step 6: Blueprint Binding Timing and Initialization Order

A subtler cause of missing overlaps is binding the delegate too early or too late. If you bind OnComponentBeginOverlap in the Blueprint constructor (Construction Script) rather than in BeginPlay, the binding may be cleared during actor initialization. Conversely, if you are spawning one actor from another and binding immediately after SpawnActor, the spawned actor may not have fully initialized its components yet.

The reliable pattern is to bind in BeginPlay and, if needed, add a one-frame delay via a SetTimer call with a delay of 0.0f to push the bind to the next tick after all actors have completed their BeginPlay calls:

void AMyActor::BeginPlay()
{
  Super::BeginPlay();
  // Defer one frame so spawned actors are fully initialized
  FTimerHandle BindTimer;
  GetWorldTimerManager().SetTimer(
    BindTimer,
    [this]() {
      OverlapBox->OnComponentBeginOverlap.AddDynamic(
        this, &AMyActor::OnOverlapBegin
      );
    },
    0.0f,
    false
  );
}

This pattern is especially useful when the overlapping actor is spawned dynamically and its collision components complete initialization asynchronously.

“Overlap events in Unreal are an opt-in system with bilateral consent — both actors have to want it, with matching channel responses, movable mobility, and a valid binding. Any one missing piece and the event never arrives.”

Run through the checklist top to bottom before opening a support thread — 95% of overlap bugs are solved by step two.