unicity-aos/aos-ce · warning
policy_rules failed to parse
Error message
policy_rules failed to parse: {e} What it means
This warning is logged in `load_rules` when the policy_rules environment variable is set and non-empty but its content is not valid JSON matching Vec<Rule>. serde_json::from_str fails, the failure is audited as `parse_error`, and an empty rule list is returned — so the broker silently runs with no policy rules even though configuration was supplied.
Solutions
- Validate the variable content with `echo "$POLICY_RULES" | python3 -m json.tool` (or jq) and fix the JSON syntax per the serde error message.
- Ensure the value is a JSON ARRAY of Rule objects with exactly the fields the Rule struct expects (correct types, no unknown/missing required fields).
- If the value is large, load it from a file instead of an env var to avoid shell escaping issues.
- Check for shell quoting problems: use single quotes around the JSON and avoid interpolation.
Example fix
// before
export POLICY_RULES="{'deny': ['fs_write']}" // not JSON, single quotes
// after
export POLICY_RULES='[{"action":"deny","tool":"fs_write"}]' Defensive patterns
Strategy: validation
Validate before calling
# Validate policy JSON before deploying
printf '%s' "$POLICY_RULES" | jq -e 'type == "array" and length > 0' \
|| { echo "POLICY_RULES must be a non-empty JSON array of rules"; exit 1; } Prevention
- Lint the policy JSON with jq/serde in CI before it reaches the environment.
- Use single-quoted heredocs or config files to avoid shell escaping corruption.
- Remember the failure mode is silent empty-rule-set — monitor audit_load_failure('parse_error') events.
- Write a schema test against the Rule struct and regenerate examples on struct changes.
When it happens
Trigger: POLICY_RULES_ENV contains malformed JSON: trailing commas, single quotes, unquoted keys, a JSON object instead of an array, or Rule fields with wrong types/missing required fields.
Common situations: Hand-edited env var with typos; YAML or shell-formatted rules pasted instead of JSON; schema drift after a broker upgrade changed the Rule struct; quotes mangled by shell escaping or secret-manager templating.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- policy_rules env read failed
- canonical document exceeds bound
- must not be empty
- embedded distro has no capsules
- embedded capsule has no name
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/9a8d5c24bf13b3e2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/aos-mcp-broker/src/policy.rs:276
pub(crate) fn load_rules() -> Vec<Rule> {
let raw = match env::var_opt(POLICY_RULES_ENV) {
Ok(Some(s)) if !s.trim().is_empty() => s,
Ok(_) => return Vec::new(),
Err(e) => {
audit_load_failure("env_read_error");
log::warn(format!(
"{}: policy_rules env read failed: {e:?}",
crate::profile::log_tag()
));
return Vec::new();
}
};
let parsed: Vec<Rule> = match serde_json::from_str(&raw) {
Ok(rules) => rules,
Err(e) => {
audit_load_failure("parse_error");
log::warn(format!(
"{}: policy_rules failed to parse: {e}",
crate::profile::log_tag()
));
return Vec::new();
}
};
if let Err(reason) = validate(&parsed) {
audit_load_failure(reason);
log::warn(format!(
"{}: policy_rules rejected ({reason}); policy NOT in force",
crate::profile::log_tag()
));
return Vec::new();
}
parsed
}
View on GitHub (pinned to f6f22024fb)