Quick answer: The most common causes are: the LayerMask parameter is filtering out the target's layer, the ray origin is inside the collider you are trying to hit (raycasts do not detect colliders they start inside), the maxDistance is too short, or you are mixing up 2D and 3D raycasts. Use Debug.

Here is how to fix Unity RayCast not hitting collider. You call Physics.Raycast expecting it to detect an enemy, a wall, or the ground — and it returns false every time. No hit, no data, no error message. You have confirmed the collider is there, the object is in the scene, and the ray should be pointing right at it. Raycast failures are notoriously hard to debug because there is no visual feedback by default. The problem is almost always a layer mask misconfiguration, a ray starting inside the target collider, or a 2D/3D mismatch.

The Symptom

Physics.Raycast returns false even though the ray should clearly be hitting a collider. You may have tested by placing a large cube directly in front of the ray origin, and it still returns no hit. Alternatively, the raycast hits some objects but not others, or it worked previously but stopped after you changed layers or reorganized your scene hierarchy.

In 2D games, you may be calling Physics.Raycast instead of Physics2D.Raycast and getting no results because 3D raycasts cannot detect 2D colliders. Another common variant is that the raycast detects the object it originates from (the player's own collider) instead of the intended target.

What Causes This

Unity's raycast system is precise and unforgiving about its parameters. Here are the most common reasons a raycast fails to hit:

The Fix

Step 1: Visualize the ray with Debug.DrawRay and fix the layer mask. Always start debugging raycasts by drawing them. Debug.DrawRay shows the ray in the Scene view so you can visually confirm its origin, direction, and length. Then verify your layer mask is constructed correctly.

using UnityEngine;

public class RaycastDebugger : MonoBehaviour
{
    [SerializeField] private LayerMask targetLayers;
    [SerializeField] private float rayDistance = 100f;

    private void Update()
    {
        Vector3 origin = transform.position;
        Vector3 direction = transform.forward;

        // ALWAYS visualize your ray. Visible in Scene view during Play Mode.
        Debug.DrawRay(origin, direction * rayDistance, Color.red);

        // Use the LayerMask field — Unity's Inspector handles the bitmask for you
        if (Physics.Raycast(origin, direction, out RaycastHit hit, rayDistance, targetLayers))
        {
            Debug.Log("Hit: " + hit.collider.gameObject.name +
                " at distance " + hit.distance);

            // Draw a green line to the hit point
            Debug.DrawLine(origin, hit.point, Color.green);
        }

        // WRONG: passing layer index directly
        // int enemyLayer = LayerMask.NameToLayer("Enemy"); // returns 8
        // Physics.Raycast(origin, direction, out hit, rayDistance, enemyLayer); // BUG!

        // CORRECT: convert layer index to bitmask
        // int enemyMask = 1 << LayerMask.NameToLayer("Enemy");
        // Physics.Raycast(origin, direction, out hit, rayDistance, enemyMask);

        // ALSO CORRECT: use LayerMask.GetMask for readability
        // int mask = LayerMask.GetMask("Enemy", "Obstacle");
        // Physics.Raycast(origin, direction, out hit, rayDistance, mask);
    }
}

Step 2: Fix the ray origin and maxDistance. Make sure the ray does not start inside the collider you want to hit. A common pattern is to offset the origin slightly forward from the caster's collider, or to use a specific empty transform as the ray origin point. Also ensure maxDistance is large enough to reach the target.

using UnityEngine;

public class WeaponRaycast : MonoBehaviour
{
    [SerializeField] private Transform muzzlePoint;
    [SerializeField] private LayerMask hitLayers;
    [SerializeField] private float maxRange = 200f;

    public void Fire()
    {
        // Use a dedicated muzzle transform so the ray starts outside the player
        Vector3 origin = muzzlePoint.position;
        Vector3 direction = muzzlePoint.forward;

        // Visualize the ray for debugging
        Debug.DrawRay(origin, direction * maxRange, Color.yellow, 1f);

        if (Physics.Raycast(origin, direction, out RaycastHit hit, maxRange, hitLayers))
        {
            Debug.Log("Hit: " + hit.collider.name + " on layer " +
                LayerMask.LayerToName(hit.collider.gameObject.layer));

            // Apply damage if the target has a health component
            var health = hit.collider.GetComponent<HealthComponent>();
            if (health != null)
                health.TakeDamage(25);
        }
        else
        {
            Debug.Log("Raycast missed. Origin: " + origin +
                ", Direction: " + direction +
                ", Distance: " + maxRange);
        }
    }

    // Ignore the caster's own colliders
    public void FireIgnoringSelf()
    {
        Vector3 origin = muzzlePoint.position;
        Vector3 direction = muzzlePoint.forward;

        RaycastHit[] hits = Physics.RaycastAll(origin, direction, maxRange, hitLayers);

        foreach (RaycastHit hit in hits)
        {
            // Skip hits on our own GameObject or children
            if (hit.transform.IsChildOf(transform))
                continue;

            Debug.Log("First valid hit: " + hit.collider.name);
            break;
        }
    }
}

Step 3: Match 2D vs 3D and configure trigger interaction. If your game uses 2D physics, you must use Physics2D.Raycast instead of Physics.Raycast. The API is slightly different — Physics2D.Raycast returns a RaycastHit2D struct, and you check its collider property for null instead of checking a boolean return value. For trigger colliders, explicitly set QueryTriggerInteraction.

using UnityEngine;

public class RaycastExamples : MonoBehaviour
{
    [SerializeField] private LayerMask targetLayers;

    // 3D Raycast with explicit trigger handling
    private void Raycast3D()
    {
        Vector3 origin = transform.position;
        Vector3 direction = transform.forward;

        // Explicitly include trigger colliders in the raycast
        if (Physics.Raycast(origin, direction, out RaycastHit hit, 100f,
            targetLayers, QueryTriggerInteraction.Collide))
        {
            Debug.Log("3D hit: " + hit.collider.name);
            Debug.Log("Is trigger: " + hit.collider.isTrigger);
        }
    }

    // 2D Raycast — completely separate physics system
    private void Raycast2D()
    {
        Vector2 origin = transform.position;
        Vector2 direction = Vector2.right;

        // Physics2D.Raycast returns a RaycastHit2D struct
        RaycastHit2D hit = Physics2D.Raycast(origin, direction, 100f, targetLayers);

        // Check the collider property, not a boolean return value
        if (hit.collider != null)
        {
            Debug.Log("2D hit: " + hit.collider.name);
            Debug.Log("Hit point: " + hit.point);
            Debug.Log("Hit distance: " + hit.distance);
        }

        // Visualize in 2D
        Debug.DrawRay(origin, direction * 100f, Color.red);
    }

    // Camera-based raycast for mouse picking
    private void MouseRaycast()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        // Debug the ray
        Debug.DrawRay(ray.origin, ray.direction * 500f, Color.cyan);

        if (Physics.Raycast(ray, out RaycastHit hit, 500f, targetLayers))
        {
            Debug.Log("Mouse hit: " + hit.collider.name);
        }
    }
}

A quick summary of the debugging checklist for raycast issues:

Related Issues

See also: Fix: Unity OnCollisionEnter Not Being Called.

See also: Fix: Unity ScriptableObject Data Lost After Exiting Play Mode.

Debug.DrawRay is your best friend. Always visualize before debugging logic.