Skip to content

Caveats & Gotchas (v2)

Gotcha What happens Fix
A scanned header includes an unparseable dependency libclang may silently degrade template types in generated bindings Keep scanned headers to standard headers, dart_cpp_bridge/*, and stdexec/execution.hpp; move heavy includes to api_impl/*.cpp
A type alias or using namespace is used The parser may not resolve the public type Use fully qualified concrete types
Generated files are edited by hand The next generation overwrites the change Edit API headers or implementations, then run dcb_gen_tool generate
A build hook is expected to regenerate code Native Assets only compiles and links Regenerate after API signature changes
Gotcha What happens Fix
Blocking an io scheduler runner That runner is unavailable while blocked; if all runners block, the whole scheduler stalls Use dcb::spawn_blocking or BRIDGE_NORMAL
dcb::sync_wait on an io scheduler runner The wrapper rejects it; raw stdexec::sync_wait can deadlock when all runners wait on the same scheduler Call it only from a worker or external thread
DartFn inside BRIDGE_SYNC Dart cannot reply while the sync call blocks Use BRIDGE_ASYNC, BRIDGE_NORMAL, or an explicit offload
A coroutine lambda captures request state Lazy resumption can outlive the full expression Use a zero-capture IIFE and pass state as parameters
Gotcha What happens Fix
Expecting Dart to force-cancel a Future A Dart Future cannot interrupt native work Expose a task ID and propagate a stdexec stop token
Cancelling a stream subscription Dart stops receiving, but native work may continue Stop the producer explicitly or accept late sink calls being dropped
Destroying a scheduler with pending work Operations may retain scheduler references Request stop and drain the structured-concurrency scope first
Gotcha What happens Fix
A worker isolate calls shutdown() It closes every session and stops the process-wide Runtime Only the main isolate calls shutdown() at process exit
An opaque object crosses isolates Handles are scoped to their Session Keep each object in its owning isolate
Native code is used after dispose() The session is closed Re-initialize or finish work before disposing

The C bridge API remains independent of the C++ async model. Its C side creates, completes, and cancels operations; a C++ caller can await the result with dcb::async_wait.

For libuv, glib, or custom loops, implement a plain stdexec scheduler. Do not reintroduce the v1 ForeignExecutor registration API.