{"record":{"id":"a923e799f183d34b","repo":"unicity-aos/aos-ce","slug":"subscribe-key-sets-priority-without-a-handler","errorCode":null,"errorMessage":"Subscribe `{key}` sets `priority` without a `handler`.","messagePattern":"Subscribe `(.+?)` sets `priority` without a `handler`\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"capsules/capsule-forge/src/checks.rs","lineNumber":233,"sourceCode":"        .map(|t| t.keys().cloned().collect())\n        .unwrap_or_default()\n}\n\n/// Check the mandatory tool-bus wiring: each `tool.v1.execute.<x>` subscribe has\n/// a handler, the two mandatory publish keys exist, and the describe request is\n/// subscribed.\nfn check_tool_bus(sub_keys: &[String], pub_keys: &[String], root: &Toml, out: &mut Vec<Finding>) {\n    let sub_table = root.get(\"subscribe\").and_then(Toml::as_table);\n    let mut saw_execute_tool = false;\n\n    for key in sub_keys {\n        if let Some(entry) = sub_table.and_then(|table| table.get(key)) {\n            let has_handler = entry\n                .get(\"handler\")\n                .and_then(Toml::as_str)\n                .is_some_and(|handler| !handler.is_empty());\n            if entry.get(\"priority\").is_some() && !has_handler {\n                out.push(Finding::err(\n                    format!(\"Subscribe `{key}` sets `priority` without a `handler`.\"),\n                    \"Add a real handler binding or remove priority from the ACL-only subscription.\",\n                ));\n            }\n            if let Some(priority) = entry.get(\"priority\") {\n                if let Some(priority) = priority.as_integer() {\n                    if !(0..=u32::MAX.into()).contains(&priority) {\n                        out.push(Finding::err(\n                            format!(\"Subscribe `{key}` has priority outside the u32 range.\"),\n                            \"Use an integer from 0 through 4294967295; lower values run first.\",\n                        ));\n                    }\n                } else {\n                    out.push(Finding::err(\n                        format!(\"Subscribe `{key}` priority must be an integer.\"),\n                        \"Use an integer from 0 through 4294967295; lower values run first.\",\n                    ));\n                }","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/capsules/capsule-forge/src/checks.rs#L215-L251","documentation":"`check_tool_bus` validates bus subscription entries: `priority` only makes sense for subscriptions that carry a `handler` binding. If a subscribe entry sets `priority` but has no non-empty `handler` string (e.g. an ACL-only subscription), this error is emitted for the offending key. Priority without a handler is meaningless scheduling metadata the runtime cannot use.","triggerScenarios":"A subscription entry under the subscribe table with `priority = 5` but no `handler` key, or `handler = \"\"` (empty string fails `has_handler`).","commonSituations":"Copying a handler subscription template and stripping the handler but leaving priority, configuring ACL-only subscriptions that previously shared a table with handler entries, or hand-merging two subscription configs.","solutions":["Add a real `handler` binding to the `{key}` subscription so `priority` is meaningful.","Remove the `priority` key from the ACL-only subscription if no handler is intended.","Split ACL-only subscriptions from handler subscriptions in the manifest to keep them structurally distinct."],"exampleFix":"// before\n[tool_bus.subscribe.events]\npriority = 5\n\n// after\n[tool_bus.subscribe.events]\nhandler = \"my_handler\"\npriority = 5","handlingStrategy":"validation","validationCode":"// Rust\nif entry.get(\"priority\").is_some()\n    && !entry.get(\"handler\").and_then(|h| h.as_str()).map_or(false, |h| !h.is_empty())\n{\n    return Err(format!(\"subscribe `{key}`: priority requires handler\"));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only add `priority` to subscriptions that also declare a non-empty `handler`.","Keep ACL-only subscriptions and handler subscriptions as separate entries.","Review subscription tables whenever copying entries between manifests."],"tags":["toml","schema-validation","config","event-bus"],"backgroundTag":"conflicting-config-options","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}