Quick answer: Godot 4 C# TaskCompletionSource<T> await resuming on a background thread? Default thread continuation - set RunContinuationsAsynchronously and route through Godot's sync context.
Custom async API uses TCS. Continuation runs on background; Node touches throw.
RunContinuationsAsynchronously
new TaskCompletionSource<T>(
TaskCreationOptions.RunContinuationsAsynchronously)Continuations queued; don't run on the SetResult thread.
Route through CallDeferred
Inside the continuation, CallDeferred to reach main. Explicit thread bridging.
Or capture context
Capture SynchronizationContext.Current at await time; post continuation to it. Cleaner if context is installed.
“TCS continuations have default thread behavior. The default isn't main.”
Build a GodotTaskCompletionSource wrapper that handles context. Misuse-resistant; reusable.