{"record":{"id":"acdae31ee346d4f1","repo":"stalwartlabs/stalwart","slug":"incorrect-number-of-task-channels","errorCode":null,"errorMessage":"Incorrect number of task channels","messagePattern":"Incorrect number of task channels","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/services/src/task_manager/manager.rs","lineNumber":296,"sourceCode":"                                err.id(job.id)\n                                    .details(\"Failed to retrieve task details.\")\n                                    .caused_by(trc::location!())\n                            );\n                        }\n                    }\n\n                    if refresh_queue || rx.is_empty() {\n                        server.notify_task_queue();\n                    }\n                }\n            });\n        }\n    }\n\n    const REFRESH_INTERVAL: Duration = Duration::from_secs(60);\n    tokio::spawn(async move {\n        let mut ipc = TaskManagerIpc {\n            txs: txs.try_into().expect(\"Incorrect number of task channels\"),\n            locked: Default::default(),\n            revision: 0,\n        };\n        let rx = inner.ipc.task_tx.clone();\n        loop {\n            // Index any queued tasks\n            let mut sleep_for = inner.build_server().process_tasks(&mut ipc).await;\n            if is_clustered && sleep_for > REFRESH_INTERVAL {\n                sleep_for = REFRESH_INTERVAL;\n            }\n\n            // Wait for a signal or sleep until the next task is due\n            let _ = tokio::time::timeout(sleep_for, rx.notified()).await;\n        }\n    });\n}\n\npub(crate) trait TaskQueueManager: Sync + Send {","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/services/src/task_manager/manager.rs#L278-L314","documentation":"The spawned TaskManager IPC worker expects the vector of task channels to convert into a fixed-size array via `try_into()`. This panic fires when the number of channels does not match the expected fixed count (TaskIpc count), which would be an internal bug — the channel vector was built with a different length than the array type expects.","triggerScenarios":"An internal invariant violation: the number of task senders collected into `txs` differs from the fixed array size expected by TaskManagerIpc, typically after adding/removing a task type in one place but not the other.","commonSituations":"Developers adding a new task/subsystem to the task manager without updating the fixed channel count; merging partial refactors of the task registry.","solutions":["Update the expected channel count / array type in TaskManagerIpc to match the number of spawned task channels","Check the code that builds `txs` and ensure every task type registers exactly one channel","Add a length assertion when building `txs` to fail fast with a clearer message"],"exampleFix":"// before\nlet ipc = TaskManagerIpc {\n    txs: txs.try_into().expect(\"Incorrect number of task channels\"),\n// after\nassert_eq!(txs.len(), NUM_TASK_TYPES, \"task channel count mismatch\");\nlet ipc = TaskManagerIpc {\n    txs: txs.try_into().unwrap(),","handlingStrategy":"validation","validationCode":"assert_eq!(txs.len(), EXPECTED_TASK_CHANNEL_COUNT, \"Incorrect number of task channels\");","typeGuard":"fn is_expected_count(txs: &[Sender<Task>]) -> bool { txs.len() == EXPECTED_TASK_CHANNEL_COUNT }","tryCatchPattern":"let Ok(arr) = <[...; N]>::try_into(txs) else {\n    panic!(\"task channel count mismatch: got {}, want {}\", txs.len(), N);\n};","preventionTips":["Derive the channel count from a single constant shared by producer and consumer","Add a unit test asserting the number of registered task types matches the fixed array size","When adding a task type, update both registration and the TaskManagerIpc array type"],"tags":["internal","ipc","tokio","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}