Quick answer: Defer the change with call_deferred (or set_deferred) so it runs after the locked phase, rather than modifying the tree during physics or a signal.
A can't-change-state error is modifying the tree while it is locked. Deferring fixes it. Here is how.
How to fix it
1. Defer with call_deferred
Wrap the structural change (add_child, remove_child, free) in call_deferred so it runs after the current physics or signal phase, when the tree is no longer locked. This is the standard fix for this error.
2. Use set_deferred for properties
For setting a property that is locked during physics (some physics properties), use set_deferred so the change applies safely after the physics step rather than during it.
3. Avoid structural changes in callbacks
Where possible, do not add or remove nodes directly inside physics callbacks or signal handlers. Queue the change and apply it deferred, so you never modify the tree while it is locked against changes.
Catching the ones you can't reproduce
The hardest version of this to fix is the one you can't reproduce — it only happens on a player's hardware, OS, driver, or save state, under conditions that simply aren't present on your machine. A report that says “it crashed” or “it froze” gives you nothing to act on, so the bug survives release after release while quietly costing you players.
Automatic error capture closes that gap. Each failure arrives with its full stack trace, the device and OS, the build number, and a breadcrumb trail of what the player did right before it broke, so even a failure you have never seen becomes a specific, reproducible issue. Fold identical failures into one signature ranked by how many players each hits, and your worklist sorts itself worst-first instead of arriving as a stream of vague complaints.
This is where a tool like Bugnet earns its place. Its SDK captures every Godot error automatically with the full stack trace plus device, OS, memory, build, and game-state context, folds duplicates into one grouped issue with an occurrence count, and ties each to the build it first appeared on — so you fix the problem that hurts the most players first and confirm it is gone when its signature disappears from the next release.
A crash you can name from its stack trace is a crash you can usually fix in minutes.