Random: NullReferenceException: Object reference not set to an instance of an object

I’m working on a shoot em up game. And sometimes when my enemies die the error appears in the console. I Instantiate random enemy prefabs. All with the right tag, every variable is set in the inspector.
The error appears on like 5 - 10% of killed enemies. It was working the whole time.

NullReferenceException: Object reference not set to an instance of an object
EnemyController.TakeDamage (Single damage) (at Assets/Scripts/EnemyController.cs:98)
UnityEngine.Component:SendMessage(String, Object)
Shot:OnTriggerEnter2D(Collider2D) (at Assets/Scripts/Shot.cs:28)

Shot.cs:28+

    void OnTriggerEnter2D(Collider2D col)
    {
        if(col.tag == "player" && this.gameObject.tag == "enemyShot")
        {
            col.SendMessage("TakeDamage", damage);
            Destroy(this.gameObject);
        }

        if(col.tag == "enemy" && this.gameObject.tag == "playerShot")
        {
            col.SendMessage("TakeDamage", damage); //28
            Destroy(this.gameObject);
        }
    }

EnemyController.cs

    protected void Die()
    {
        Punktanzeige.SendMessage("AddPoints", ScorePoints);
        Instantiate(explosion, this.gameObject.transform.position, this.gameObject.transform.rotation);

        this.GetComponent<DropController>().SpawnPowerUp();

        speaker.PlayOneShot(destroySound);
        Destroy(this.gameObject);
    }

    protected void TakeDamage(float damage)
    {

        speaker.PlayOneShot(hitSound); //98
        sr.sprite = hitSprite;
        nextSprite = Time.time + hitEffectTime;
        hp -= damage;

        if (hp <= 0)
        {
            Die();
        }
    }

I’m gonna go with a race condition on this one. Collision callbacks have caused some sticky situations for me in the past.

I think on occasion there are multiple shots that would cause the enemy to destroy itself. One gets there first and the code drops out from under its feet (so to speak) in the middle of execution. That’s why the null reference doesn’t go away when you remove what appears to be the offending line – the whole object is now null.

Have you considered using an object pool? It’s a better option usually than instantiation/destroying. Instead of destroying the enemy, disable it – with gameObject.SetActive(false); – and return it to the pool.

I’m pretty sure you won’t run into any null references if you do this.

I think the problem is that you aren’t calling the behaviour. Since you are calling snedMessage on the collider it won’t work. Since the collider doesn’t have a function called TakeDamage. Try replacing send message with the following:

void OnTriggerEnter2D(Collider2D col)
     {
         if(col.tag == "player" && this.gameObject.tag == "enemyShot")
         {
             col.GetComponent<EnemyController>().TakeDamage(damage);
             Destroy(this.gameObject);
         }
 
         if(col.tag == "enemy" && this.gameObject.tag == "playerShot")
        {
            col.GetComponent<EnemyController>().TakeDamage(damage);
             Destroy(this.gameObject);
         }
     }