unicity-aos/aos-ce · warning · Finding
[env]. sets scope = "shared", which is silently ignored.
Error message
[env].{key} sets scope = "shared", which is silently ignored. What it means
check_env inspects each [env] entry in the manifest and warns when an entry sets scope = "shared". Manifest-declared env scope is silently ignored by the host — the field has no effect — so forge warns authors to remove it rather than rely on a no-op setting.
Solutions
- Remove the `scope` key from the [env] entry; it is never honored from the manifest.
- If sharing is required, configure shared/operator env scope through the host/operator configuration, not the manifest.
- Keep only plain value entries under [env] (e.g. `[env.MY_VAR]\nvalue = "x"`).
Example fix
# before [env.API_URL] value = "https://api.example.com" scope = "shared" # after [env.API_URL] value = "https://api.example.com"
Defensive patterns
Strategy: validation
Validate before calling
# fail CI if any env entry carries a scope key grep -n 'scope' capsule.toml && echo "manifest env scope is ignored; remove it" && exit 1
Prevention
- Keep [env] entries to plain key/value pairs only
- Configure shared env at the host/operator layer, not the manifest
- Run forge validate before every capsule release
When it happens
Trigger: validate_manifest -> check_env finds any env table entry whose `scope` sub-value is the string "shared"; e.g. `[env.MY_VAR]\nscope = "shared"`.
Common situations: Authors assuming manifest env can be shared with the operator or other capsules; copying an env block from an old manifest format where scope was honored; cargo-culting config from a different capsule system.
Related errors
- Subscribe ` ` has priority outside the u32 range.
- Subscribe ` ` priority must be an integer.
- Subscribe ` ` has no `handler`.
- Mandatory publish key
- Subscribe `tool.v1.request.describe` is missing — tools…
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/7dbad1ca0e783408.
Report an issue: GitHub.
Appendix: source
Thrown at capsules/capsule-forge/src/checks.rs:184
.and_then(Toml::as_str)
.is_some_and(|f| !f.is_empty())
})
});
if !has_file {
out.push(Finding::err(
"No [[component]] with a `file` was found.",
"Add a [[component]] table with `id`, `file = \"my_capsule.wasm\"`, `type = \"executable\"`.",
));
}
}
fn check_env(root: &Toml, out: &mut Vec<Finding>) {
let Some(env) = root.get("env").and_then(Toml::as_table) else {
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.*`.",
));
}View on GitHub (pinned to f6f22024fb)