unicity-aos/aos-ce · error

Subscribe ` ` priority must be an integer.

Error message

Subscribe `{key}` priority must be an integer.

What it means

capsule-forge validates that a [subscribe] entry's `priority` is an integer (via TOML as_integer). If `priority` is present but is a string, float, or boolean, the type cannot back the u32 dispatcher, so validation emits this error with guidance to use an integer 0..4294967295.

Solutions

  1. Change `priority` in the [subscribe] row to an unquoted integer between 0 and 4294967295.
  2. Remove quotes around numeric values if the manifest was generated from another format.
  3. Re-run `capsule-forge validate` to verify.

Example fix

// before ([subscribe])
"tool.v1.request.describe" = { wit = ..., handler = "tool_describe", priority = "10" }
// after
"tool.v1.request.describe" = { wit = ..., handler = "tool_describe", priority = 10 }
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate TOML priority type before validating the manifest
if let Some(p) = row.get("priority") {
    assert!(p.is_integer(), "priority must be an integer");
}

Type guard

fn priority_is_integer(v: &toml::Value) -> bool { v.is_integer() }

Prevention

When it happens

Trigger: validate_manifest -> check_tool_bus sees a [subscribe] key with a `priority` field whose TOML value is not an integer (e.g. `priority = "10"` or `priority = 1.5`).

Common situations: Quoting the priority by accident, using a float for readability, or generating the manifest from YAML/JSON where numbers were serialized as strings.

Related errors


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

Appendix: source

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

                .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.",
                    ));
                }
            }
        }

        let Some(tool) = key.strip_prefix("tool.v1.execute.") else {
            continue;
        };
        // The `*.result` publish key would also strip; skip non-tool shapes.
        if tool.contains('*') || tool.contains('.') {
            continue;
        }
        saw_execute_tool = true;
        let has_handler = sub_table
            .and_then(|t| t.get(key))
            .and_then(|v| v.get("handler"))

View on GitHub (pinned to f6f22024fb)