Skip to content

Why can't I change this state while flushing queries?

Godot 4.x

You’ll see something like one of these in the Debugger panel. The function name will be your own:

_on_body_entered(): Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead.
_on_body_entered(): Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead.
What’s happeningGo to
You set disabled on a CollisionShape2D or CollisionShape3DDisabling the collision shape
You call queue_free() on an Area2D, a body, or their parentFreeing the body or area
You set monitoring or monitorableTurning monitoring on or off
You change scene from the callbackChanging scene from the callback

Coin is an Area2D with its body_entered signal connected to its own script. All the errors below happen inside that handler.

  • LevelNode2D
    • PlayerCharacterBody2D
    • CoinArea2Dhas scriptbody_entered connected here
      • CollisionShape2DCollisionShape2D

body_entered runs in the middle of the physics step, while Godot is still working through the list of collisions it found. Changing collision objects at that moment would alter the list it is reading, so Godot refuses and asks you to wait until the step is over. That’s what “deferred” means: do it at the end of the frame instead of right now.

The natural way to stop a coin being collected twice is to switch off its shape, but setting disabled directly in the handler is a collision change in the middle of the physics step.

coin.gd
extends Area2D
func _on_body_entered(body: Node2D) -> void:
$CollisionShape2D.disabled = true
$CollisionShape2D.set_deferred("disabled", true)
hide()

set_deferred() takes the property name as a string and the value to set. Godot applies it once the physics step is done.

Freeing the coin from its own body_entered gives the second error, because the coin is a CollisionObject2D and removing it mid-step is the same problem. Call queue_free() deferred instead:

coin.gd
func _on_body_entered(body: Node2D) -> void:
queue_free()
queue_free.call_deferred()

call_deferred("queue_free") with a string does the same thing. This only matters for nodes that take part in collision: freeing a plain Node2D, a Sprite2D or a Label from the callback is fine.

monitoring is the Area2D property that decides whether it detects bodies at all. Switching it off inside the handler is exactly the state the first error is talking about:

coin.gd
func _on_body_entered(body: Node2D) -> void:
monitoring = false
set_deferred("monitoring", false)

The same goes for monitorable, and for the collision layer and mask properties.

Changing scene frees the whole current scene, collision objects included, so from a physics callback it needs deferring too: get_tree().change_scene_to_file.call_deferred("res://next.tscn"). See How do I change scenes? for the rest.

Click the error in the Debugger panel and read the stack trace. The physics callback, _on_body_entered or _on_area_entered, sits at the top, and every line below it ran as part of that callback. Anything in that chain that disables a shape, frees a body or area, or toggles monitoring needs to go through set_deferred() or call_deferred(), even if it lives in another function or another node.