unicity-aos/aos-ce · warning · Finding
[publish] is empty or missing — the capsule cannot publish…
Error message
[publish] is empty or missing — the capsule cannot publish any event.
What it means
collect_topics gathers keys from the manifest's [publish] table and warns when it is empty or absent. Publishing is fail-closed: a capsule with no declared publish topics cannot publish any event on the bus. Forge warns because the standard tool-bus capsules are expected to publish tool results and describe responses.
Solutions
- Add a [publish] section with the tool-bus keys `tool.v1.execute.*.result` and `tool.v1.response.describe.*`.
- If the capsule genuinely publishes nothing, acknowledge the warning is intentional and leave it (behavior is fail-closed by design).
- Re-run forge validate after adding topics to confirm the warning clears.
Example fix
# before
[subscribe]
"tool.v1.execute.echo" = {}
# after
[subscribe]
"tool.v1.execute.echo" = {}
[publish]
"tool.v1.execute.*.result" = {}
"tool.v1.response.describe.*" = {} Defensive patterns
Strategy: validation
Validate before calling
# ensure [publish] exists with required keys before shipping tomlq '.publish | keys' capsule.toml | grep -q 'tool.v1.execute.*.result' || echo "missing publish topics"
Prevention
- Start tool capsules from the forge template that includes [publish]
- Never delete publish keys during refactors without re-validating
- Run forge validate in CI on every manifest
When it happens
Trigger: validate_manifest -> collect_topics finds table_keys(root, "publish") empty — either the [publish] section is missing from the manifest or it contains no topic keys.
Common situations: New capsule scaffolded with only a [subscribe] section; author deleting publish entries after refactoring; template manifest for a purely-subscribing capsule reused for a tool capsule that must reply on the tool bus.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- [subscribe] is empty or missing — the capsule cannot…
- Topic ` ` has more than 8 segments — likely a mistake.
- embedded capsule source is not canonical
- Subscribe ` ` has priority outside the u32 range.
- Subscribe ` ` priority must be an integer.
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/8c576ba81b1a47b7.
Report an issue: GitHub.
Appendix: source
Thrown at capsules/capsule-forge/src/checks.rs:198
return;
};
for (key, val) in env {
if val.get("scope").and_then(Toml::as_str) == Some("shared") {
out.push(Finding::warn(
format!("[env].{key} sets scope = \"shared\", which is silently ignored."),
"Remove `scope`; shared/operator-only env scope is not honoured from the manifest.",
));
}
}
}
/// Collect the `[publish]` and `[subscribe]` topic keys, warning if a table is
/// empty (fail-closed: the capsule then can't publish/subscribe at all).
fn collect_topics(root: &Toml, out: &mut Vec<Finding>) -> (Vec<String>, Vec<String>) {
let pub_keys = table_keys(root, "publish");
let sub_keys = table_keys(root, "subscribe");
if pub_keys.is_empty() {
out.push(Finding::warn(
"[publish] is empty or missing — the capsule cannot publish any event.",
"Add the tool-bus publish keys `tool.v1.execute.*.result` and `tool.v1.response.describe.*`.",
));
}
if sub_keys.is_empty() {
out.push(Finding::warn(
"[subscribe] is empty or missing — the capsule cannot receive any event.",
"Add one `tool.v1.execute.<tool>` per tool plus `tool.v1.request.describe`.",
));
}
(pub_keys, sub_keys)
}
fn table_keys(root: &Toml, table: &str) -> Vec<String> {
root.get(table)
.and_then(Toml::as_table)
.map(|t| t.keys().cloned().collect())
.unwrap_or_default()View on GitHub (pinned to f6f22024fb)