Quick answer: Two static colliders never produce trigger events. One side must have a Rigidbody (kinematic is fine). Verify Is Trigger is checked, both GameObjects are active, and the layer collision matrix allows the layer pair to interact.
Here is how to fix Unity trigger collider not detecting overlaps. You build a pickup: a GameObject with a sphere collider, Is Trigger checked, a script with OnTriggerEnter. The player walks through it. Nothing happens. You check the console, add a Debug.Log, still nothing. Unity’s trigger system has specific rules about which combinations of colliders and rigidbodies fire events, and two static sides is the one setup that produces no callbacks.
The Symptom
OnTriggerEnter, OnTriggerStay, and OnTriggerExit do not fire when colliders overlap. The same setup that works in one project fails in another. Adding Debug.Log inside the callback never triggers. Physics debug visualization shows the colliders overlapping correctly, but no events fire.
What Causes This
No Rigidbody on either side. Unity’s physics engine distinguishes static colliders (no Rigidbody) from dynamic/kinematic colliders (with Rigidbody). Two static colliders produce no trigger events, only OnTriggerEnter requires at least one side to be dynamic or kinematic. This is a PhysX optimization — static/static interactions would otherwise require O(n²) checks on every frame.
Is Trigger unchecked. If neither collider has Is Trigger checked, they collide physically but do not fire trigger events — OnCollisionEnter fires instead. If both are marked Is Trigger, both fire trigger events.
Layer matrix blocks the pair. If you customized the collision matrix (Project Settings > Physics > Layer Collision Matrix) and unchecked the cell for the two objects’ layers, the physics engine ignores the pair entirely — including triggers.
GameObject or component disabled. A disabled GameObject does not produce physics events. A disabled Collider component does not fire. The script containing OnTriggerEnter must also be on an enabled component of the trigger or the overlapping object.
Script on the wrong GameObject. OnTriggerEnter fires on the GameObject of the script only if that GameObject has one of the colliders. Adding the script to a parent or child of the collider does not work — attach it to the same GameObject as the collider.
Collider scale or offset wrong. A collider with scale 0 in an axis has zero size in that axis. Edge-only overlaps can miss due to floating-point precision if the collider is razor thin. Always verify collider dimensions visually in the Scene view.
The Fix
Step 1: Verify the rigidbody rule. One of the two colliders must have a Rigidbody. Decision tree:
- Static trigger + moving character: add Rigidbody to the character (usually already there)
- Moving trigger + static target: add Rigidbody to the trigger (kinematic to avoid physics)
- Both moving: each should have a Rigidbody already
For a pickup GameObject with just a trigger, add a Rigidbody and check “Is Kinematic” so gravity does not affect it. The kinematic rigidbody is what registers it with the physics engine as a non-static collider.
Step 2: Double-check Is Trigger. Select each collider. Confirm “Is Trigger” is checked on the one you want to be a trigger. The Scene view draws triggers as a hollow green wireframe, physical colliders as solid green.
Step 3: Check layer matrix. Go to Project Settings > Physics > Layer Collision Matrix (for 3D) or Physics 2D > Layer Collision Matrix (for 2D). Confirm the cell at the intersection of your trigger’s layer and the overlapping object’s layer is checked. If it is not, check it.
Common misconfiguration: you set up a “Trigger” layer to separate triggers from collision, forgot to check the Trigger x Player cell, and now triggers on the Trigger layer never fire with the player.
Step 4: Write a minimal test script. To isolate, attach this to your trigger:
using UnityEngine;
public class TriggerDebug : MonoBehaviour
{
void Start()
{
var c = GetComponent<Collider>();
var rb = GetComponent<Rigidbody>();
Debug.Log($"Collider: {c}, isTrigger: {c?.isTrigger}, " +
$"Rigidbody on self: {rb}, layer: {gameObject.layer}");
}
void OnTriggerEnter(Collider other)
{
Debug.Log($"Trigger entered by {other.name} " +
$"(layer {other.gameObject.layer}, " +
$"rb: {other.attachedRigidbody})");
}
}
If Start logs but OnTriggerEnter does not, physics is not pairing the colliders. Check the conditions above methodically.
2D Differences
Unity 2D physics uses the same rules with 2D variants: Rigidbody2D, Collider2D, OnTriggerEnter2D. Same “need a rigidbody” requirement. Static-static trigger pairs produce no 2D events.
An additional 2D gotcha: the Composite Collider 2D can swallow trigger events if the component has “Used By Composite” checked on individual colliders. The composite body handles physics but the original triggers do not fire individually.
OverlapBox/OverlapSphere Alternative
If you cannot get trigger events to fire and performance is not critical, use Physics.OverlapSphere or Physics.OverlapBoxNonAlloc in Update. These query the physics scene directly without needing rigidbodies or trigger setup:
void Update()
{
Collider[] hits = Physics.OverlapSphere(transform.position, 1f);
foreach (var h in hits)
{
if (h.CompareTag("Player"))
Debug.Log("Player in range");
}
}
Slightly more CPU-expensive than triggers but bypasses all the setup gotchas. Good fallback when trigger events stubbornly refuse to fire.
“Triggers are conservative. They want to save you CPU by not firing on static-static pairs. Respect the rule, add a kinematic rigidbody.”
Related Issues
For collision (non-trigger) detection issues, see OnCollisionEnter Not Being Called. For raycasts missing colliders, Raycast Not Hitting Collider covers related physics-query issues.
Kinematic rigidbody on one side. Is Trigger on at least one. Layer matrix checked. Three rules, no missed triggers.