Quick answer: set_deferred() queues the change until the end of the current frame, so reading the property right afterwards still returns the old value. The property name is a string that must match exactly (a typo is silently ignored), and physics properties such as monitoring or a shape's disabled affect collisions only from the next physics step.

You were told to use set_deferred() to change collision settings inside a physics callback, you did, and it looks like nothing happened. Usually it did happen — just later than you checked, or on a property name that does not exist.

When the value actually changes

Deferred calls are flushed when the engine is idle at the end of the frame. Code that runs right after the call still sees the old value:

$Area2D.set_deferred("monitoring", false)
print($Area2D.monitoring)        # still true here
await get_tree().process_frame
print($Area2D.monitoring)        # false now

So set_deferred() followed immediately by logic that depends on the new value is a bug. Move that logic into the deferred step too:

func _on_body_entered(body):
    _disable_and_respawn.call_deferred()

func _disable_and_respawn():
    $Hitbox.monitoring = false
    respawn()

The property name must be exact

set_deferred("monitorng", false) does not error; it just sets nothing. Copy names from the Inspector (hover a property to see its script name) or the class reference. Note that nested values are not addressed with dots: to change a shape's disabled, call it on the CollisionShape2D node, not on the body.

$CollisionShape2D.set_deferred("disabled", true)   # correct
set_deferred("CollisionShape2D:disabled", true)    # not a property path

Physics changes need a physics step

Even after the deferred set runs, the physics server picks the change up on the next physics step. An Area turned off this frame can still report overlaps that were already queued. If you must be certain, wait for get_tree().physics_frame before relying on it.

Why you need it at all

Inside signals emitted by the physics server (body_entered, area_entered, _integrate_forces and similar), the server is iterating its data. Changing shapes, monitoring or collision layers directly can fail with "Can't change this state while flushing queries" or "Function blocked during in/out signal". Deferring the change avoids that. Outside physics callbacks, a direct assignment is fine and clearer.

The node is freed first

If the object is freed before the end of the frame, the deferred set is discarded. That is harmless, but it means a queue_free() plus set_deferred() on the same node does nothing useful.

Multiple changes

For several related changes, one deferred function is easier to reason about than a chain of set_deferred() calls, and guarantees they apply together.

Related fixes