update fails with NullReferenceException after OnTriggerEnter Destroy()s object

My Enemy.cs MonoBehaviour object has these functions

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("projectile_player"))
        {
            Destroy(gameObject);
            Destroy(collision.gameObject);
        }
    }

    void Update()
    {
        if ( (Time.time - _last_fire_time) > _fire_interval_sec )
        {
            _last_fire_time = Time.time;
            Fire();
        }
    }

Running this code, sometimes the Update() crashes with

NullReferenceException: Object reference not set to an instance of an object
Enemy.Update () (at Assets/scripts/Enemy.cs:36)

I think that the Enemy object got destroyed while its Update method was still running.
Is that possible?
Doesn’t the Unity Engine prevent that, and destroys the object only outside of Update and FixedUpdate?

Here is the entire class

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    [SerializeField] float _fire_interval_sec = 1;
    [SerializeField] float _rotate_speed = 90;
    [SerializeField] float _rotate_stop_angle = 0.5F;
    [SerializeField] float _fire_min_angle = 3;
    [SerializeField] Cannon _main_cannon;
    [SerializeField] float _flight_speed = 1;
    [SerializeField] GamePanelDimensionsSO _game_panel_dimensions;

    Vector3         _player_pos;
    float           _last_fire_time = 0;
    GameObject      _player = null;

    void Start()
    {
        _player = GameObject.FindGameObjectsWithTag("Player")[0];
    }

    // Update is called once per frame
    void Update()
    {
        if (_player == null)
            return;

        float angle = AngleToPlayer();
        float abs_angle = Math.Abs(angle);
        if (abs_angle > _rotate_stop_angle)
            Rotate(angle);

        if ( (Time.time - _last_fire_time) > _fire_interval_sec &&
            abs_angle < _fire_min_angle &&
            _game_panel_dimensions.PositionWithinGamePanel(transform.position))
        {
            _last_fire_time = Time.time;
            Fire();
        }
    }

    void FixedUpdate()
    {
        Vector3 translation = Vector3.up * (_flight_speed * Time.fixedDeltaTime);
        transform.Translate(translation);
    }

    float AngleToPlayer()
    {
        Vector3 _direction_vector = transform.rotation * Vector3.up;
        float angle = Vector3.SignedAngle(_direction_vector, _player.transform.position - transform.position, Vector3.forward);

        // Debug.Log("angle " + angle);

        return angle;
    }

    void Rotate(float angle_to_rotate_towards)
    {
        transform.Rotate(Math.Sign(angle_to_rotate_towards) * transform.forward,  _rotate_speed * Time.deltaTime);
    }

    void Fire()
    {
        _main_cannon.Fire();
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("OnTriggerEnter2D " + collision);
        if (collision.gameObject.CompareTag("projectile_player"))
        {
            Destroy(gameObject);
            Destroy(collision.gameObject);
        }
    }
}

If the mainCannon is attached to the object that contains this script, the problem is that you are destroying the object, and Unity takes one frame to destroy the object, in the frame that you call the Destroy(gameObject), the object is marked for destruction, and if you check for nullity it will return null.

In the next frame, the object is released from memory.


Try this:

 private void OnTriggerEnter2D(Collider2D collision)
 {
     Debug.Log("OnTriggerEnter2D " + collision);
     if (collision.gameObject.CompareTag("projectile_player"))
     {
         //Destroy the bullet and the enemy itself.
         Destroy(collision.gameObject);
         Destroy(gameObject);
     }
 }