Summary
Workflow.validate() loads inner nodes via asyncio.to_thread(...load_node...) in parallel. With the default NodeRegistry.DEFAULT (a LazyNodeRegistry), the first call to build() is not thread-safe; concurrent load_node() calls can race during registry freezing (e.g., both threads entering build() and deleting _registrations/_removals), causing intermittent AttributeError/KeyError during validation.
Possible fixes
- (a) Pre-freeze the registry once on the main thread before spawning threads (e.g., eagerly call
build() during ValidationContext construction).
- (b) Add a lock to
build() so only the first caller performs the freeze and others wait.
- (c) Avoid parallel
to_thread loading and load nodes sequentially in the event loop thread (likely fast enough for validation).
Notes
🤖 Generated with Claude Code
Summary
Workflow.validate()loads inner nodes viaasyncio.to_thread(...load_node...)in parallel. With the defaultNodeRegistry.DEFAULT(aLazyNodeRegistry), the first call tobuild()is not thread-safe; concurrentload_node()calls can race during registry freezing (e.g., both threads enteringbuild()and deleting_registrations/_removals), causing intermittentAttributeError/KeyErrorduring validation.Possible fixes
build()duringValidationContextconstruction).build()so only the first caller performs the freeze and others wait.to_threadloading and load nodes sequentially in the event loop thread (likely fast enough for validation).Notes
🤖 Generated with Claude Code