unicity-aos/aos-ce · error

Subscribe ` ` sets `priority` without a `handler`.

Error message

Subscribe `{key}` sets `priority` without a `handler`.

What it means

`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.

Solutions

  1. Add a real `handler` binding to the `{key}` subscription so `priority` is meaningful.
  2. Remove the `priority` key from the ACL-only subscription if no handler is intended.
  3. Split ACL-only subscriptions from handler subscriptions in the manifest to keep them structurally distinct.

Example fix

// before
[tool_bus.subscribe.events]
priority = 5

// after
[tool_bus.subscribe.events]
handler = "my_handler"
priority = 5
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if entry.get("priority").is_some()
    && !entry.get("handler").and_then(|h| h.as_str()).map_or(false, |h| !h.is_empty())
{
    return Err(format!("subscribe `{key}`: priority requires handler"));
}

Prevention

When it happens

Trigger: A subscription entry under the subscribe table with `priority = 5` but no `handler` key, or `handler = ""` (empty string fails `has_handler`).

Common situations: 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.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/a923e799f183d34b. Report an issue: GitHub.

Appendix: source

Thrown at capsules/capsule-forge/src/checks.rs:233

        .map(|t| t.keys().cloned().collect())
        .unwrap_or_default()
}

/// Check the mandatory tool-bus wiring: each `tool.v1.execute.<x>` subscribe has
/// a handler, the two mandatory publish keys exist, and the describe request is
/// subscribed.
fn check_tool_bus(sub_keys: &[String], pub_keys: &[String], root: &Toml, out: &mut Vec<Finding>) {
    let sub_table = root.get("subscribe").and_then(Toml::as_table);
    let mut saw_execute_tool = false;

    for key in sub_keys {
        if let Some(entry) = sub_table.and_then(|table| table.get(key)) {
            let has_handler = entry
                .get("handler")
                .and_then(Toml::as_str)
                .is_some_and(|handler| !handler.is_empty());
            if entry.get("priority").is_some() && !has_handler {
                out.push(Finding::err(
                    format!("Subscribe `{key}` sets `priority` without a `handler`."),
                    "Add a real handler binding or remove priority from the ACL-only subscription.",
                ));
            }
            if let Some(priority) = entry.get("priority") {
                if let Some(priority) = priority.as_integer() {
                    if !(0..=u32::MAX.into()).contains(&priority) {
                        out.push(Finding::err(
                            format!("Subscribe `{key}` has priority outside the u32 range."),
                            "Use an integer from 0 through 4294967295; lower values run first.",
                        ));
                    }
                } else {
                    out.push(Finding::err(
                        format!("Subscribe `{key}` priority must be an integer."),
                        "Use an integer from 0 through 4294967295; lower values run first.",
                    ));
                }

View on GitHub (pinned to f6f22024fb)