Symptom

Kraken’s nightly architectural scan flagged that DefaultNodeObserver handles all errors via logging only, potentially leaving node processing silently broken.

Root cause

Three issues in DefaultNodeObserver:

  1. CancellationException swallowed: The FlowCollector caught Exception without re-throwing CancellationException. In Kotlin coroutines, CancellationException is the cooperative-cancellation signal — swallowing it inside a collector means the collection loop continues even when the coroutine scope is being cancelled, defeating structured concurrency.

  2. Typo in log message: "multuiple" in the multiple-observers warning.

  3. Multiple-observers path permanently orphaned nodes: When subscriptionCount > 1 at observer setup, the inner job logged an error and exited without calling node.collect(). The node ID was added to jobs (preventing future observe() calls from re-registering), but the job never collected — so the node was permanently unobserved. This could be triggered in production by rapid UI navigation causing transient multi-subscription before the observer job started.

Fix

Prevention