Summary
A module's [[subscription]] entry naming a chain_id with no matching [chains.<id>] entry in engine.toml is not caught at boot. The engine boots successfully and the subscription's background task retries forever with only a periodic warn-level log — it never receives an event and never causes a startup failure.
Affected code
crates/nexum-runtime/src/supervisor.rs — per-module subscription validation loop (module load sequence)
crates/nexum-runtime/src/runtime/event_loop.rs — reconnecting_chain_log_task() / reconnecting_block_task()
crates/nexum-runtime/src/host/provider_pool.rs — ProviderPool chain lookups
Finding
The only boot-time validation of [[subscription]] entries checks two cases: Cron subscriptions (warns, since they're inert in 0.2) and Extension subscriptions naming an unknown event kind (hard boot error). Every other subscription kind — including chain-log and block subscriptions — falls through a _ => {} catch-all with zero validation.
open_chain_log_streams/open_block_streams spawn a reconnect task for every subscription unconditionally, with no eager chain-existence check before spawning. That task's first pool.block_number(chain) call returns ProviderError::UnknownChain, and the task's error-handling path treats this identically to a transient network failure: log a warn!, apply exponential backoff, and retry forever. There's no special case distinguishing "this chain will never exist" from "the RPC is briefly down."
Impact
The engine boots successfully, every module initializes, and everything looks healthy except for a recurring warn-level "chain-log head fetch failed — retrying after backoff" log line for a subscription that will never receive a single event. This is easy to miss in production log volume and gives no clear signal that a module is effectively dead on arrival due to a config typo (e.g. a chain_id that doesn't match any [chains.<id>] entry).
Suggested fix
Extend the existing subscription-validation loop to also check chain-log/block subscription chain_ids against engine_cfg.chains.keys(), returning a hard boot error on a mismatch — mirroring what already happens for unknown extension kinds.
Found via
Internal red-team exercise (operator mistake persona).
Summary
A module's
[[subscription]]entry naming achain_idwith no matching[chains.<id>]entry inengine.tomlis not caught at boot. The engine boots successfully and the subscription's background task retries forever with only a periodic warn-level log — it never receives an event and never causes a startup failure.Affected code
crates/nexum-runtime/src/supervisor.rs— per-module subscription validation loop (module load sequence)crates/nexum-runtime/src/runtime/event_loop.rs—reconnecting_chain_log_task()/reconnecting_block_task()crates/nexum-runtime/src/host/provider_pool.rs—ProviderPoolchain lookupsFinding
The only boot-time validation of
[[subscription]]entries checks two cases:Cronsubscriptions (warns, since they're inert in 0.2) andExtensionsubscriptions naming an unknown event kind (hard boot error). Every other subscription kind — including chain-log and block subscriptions — falls through a_ => {}catch-all with zero validation.open_chain_log_streams/open_block_streamsspawn a reconnect task for every subscription unconditionally, with no eager chain-existence check before spawning. That task's firstpool.block_number(chain)call returnsProviderError::UnknownChain, and the task's error-handling path treats this identically to a transient network failure: log awarn!, apply exponential backoff, and retry forever. There's no special case distinguishing "this chain will never exist" from "the RPC is briefly down."Impact
The engine boots successfully, every module initializes, and everything looks healthy except for a recurring warn-level "chain-log head fetch failed — retrying after backoff" log line for a subscription that will never receive a single event. This is easy to miss in production log volume and gives no clear signal that a module is effectively dead on arrival due to a config typo (e.g. a
chain_idthat doesn't match any[chains.<id>]entry).Suggested fix
Extend the existing subscription-validation loop to also check chain-log/block subscription
chain_ids againstengine_cfg.chains.keys(), returning a hard boot error on a mismatch — mirroring what already happens for unknown extension kinds.Found via
Internal red-team exercise (
operator mistakepersona).