unicity-aos/aos-ce · error
Mandatory publish key
Error message
Mandatory publish key `{required}` is missing. What it means
When a manifest declares it executes tools (`saw_execute_tool`), the tool-bus protocol requires the capsule to publish results and describe responses on two mandatory topics: `tool.v1.execute.*.result` and `tool.v1.response.describe.*`. check_tool_bus scans the [publish] keys and fails the manifest if either is missing, because downstream consumers of tool results/describe would break.
Solutions
- Add `"tool.v1.execute.*.result" = { wit = ... }` to the [publish] table.
- Add `"tool.v1.response.describe.*" = { wit = ... }` to the [publish] table.
- Re-run `capsule-forge validate` and check the sibling error for `tool.v1.request.describe` in [subscribe].
Example fix
// before ([publish])
"tool.v1.request.execute" = { wit = ... }
// after
"tool.v1.request.execute" = { wit = ... }
"tool.v1.execute.*.result" = { wit = ... }
"tool.v1.response.describe.*" = { wit = ... } Defensive patterns
Strategy: validation
Validate before calling
// Check mandatory publish keys before validating
const REQUIRED: [&str; 2] = ["tool.v1.execute.*.result", "tool.v1.response.describe.*"];
for r in REQUIRED { assert!(publish.contains_key(r), "missing {r}"); } Prevention
- Start tool capsules from the full template that already includes both publish keys.
- Add the required-topic list to a shared manifest schema/linter.
- Review any manual edit to [publish] against the tool-bus protocol checklist.
When it happens
Trigger: validate_manifest -> check_tool_bus with an execute-tool capability present but [publish] lacking `tool.v1.execute.*.result` or `tool.v1.response.describe.*`.
Common situations: Adding tool execution to a capsule without wiring result topics, trimming [publish] entries during refactoring, or copying a minimal manifest template that only covers requests.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Subscribe ` ` has priority outside the u32 range.
- Subscribe ` ` priority must be an integer.
- Subscribe ` ` has no `handler`.
- Subscribe `tool.v1.request.describe` is missing — tools…
- Topic ` ` has empty segments (leading/trailing/consecutive…
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/df1e3db442b1e8f6.
Report an issue: GitHub.
Appendix: source
Thrown at capsules/capsule-forge/src/checks.rs:279
}
saw_execute_tool = true;
let has_handler = sub_table
.and_then(|t| t.get(key))
.and_then(|v| v.get("handler"))
.and_then(Toml::as_str)
.is_some_and(|h| !h.is_empty());
if !has_handler {
out.push(Finding::err(
format!("Subscribe `{key}` has no `handler`."),
format!("Add `handler = \"tool_execute_{tool}\"` to the `{key}` row."),
));
}
}
if saw_execute_tool {
for required in ["tool.v1.execute.*.result", "tool.v1.response.describe.*"] {
if !pub_keys.iter().any(|k| k == required) {
out.push(Finding::err(
format!("Mandatory publish key `{required}` is missing."),
format!("Add `\"{required}\" = {{ wit = ... }}` to [publish]; tool results/describe break without it."),
));
}
}
if !sub_keys.iter().any(|k| k == "tool.v1.request.describe") {
out.push(Finding::err(
"Subscribe `tool.v1.request.describe` is missing — tools won't be discoverable.",
"Add `\"tool.v1.request.describe\" = { wit = ..., handler = \"tool_describe\" }` to [subscribe].",
));
}
}
}
/// Flag malformed topic keys: empty segments, or absurd depth (>8 segments).
fn check_topic_shapes(pub_keys: &[String], sub_keys: &[String], out: &mut Vec<Finding>) {
for key in pub_keys.iter().chain(sub_keys) {
if has_empty_segments(key) {View on GitHub (pinned to f6f22024fb)