unicity-aos/aos-ce · warning
policy_rules env read failed
Error message
policy_rules env read failed: {e:?} What it means
This warning is emitted in `load_rules` when reading the POLICY_RULES_ENV environment variable itself fails (env::var_opt returns Err, e.g. a non-UTF-8 value or OS-level error). The loader audits the failure as `env_read_error` and returns an empty rule set, meaning the broker runs with NO policy rules (default-allow/empty policy) rather than crashing.
Solutions
- Check how POLICY_RULES_ENV is set; unset and re-set it with valid UTF-8 JSON content.
- Inspect the value with `env | grep policy_rules` or `locale`-aware tools; replace binary/invalid bytes.
- If you intend no rules, unset the variable entirely so load_rules takes the Ok(None)/empty path.
- Verify the process supervisor (Docker, systemd, k8s) is not injecting malformed values for this key.
Example fix
// before (invalid UTF-8 bytes injected) export POLICY_RULES=$(cat rules.bin) // after export POLICY_RULES="$(cat rules.json)" # ensure valid UTF-8 JSON
Defensive patterns
Strategy: validation
Validate before calling
# Validate the env var is readable UTF-8 before launching the broker
case "$POLICY_RULES" in
'') echo "policy_rules unset/empty (no rules)" ;;
*) printf '%s' "$POLICY_RULES" | iconv -f utf-8 -t utf-8 >/dev/null \
|| echo "POLICY_RULES is not valid UTF-8" ;;
esac Prevention
- Set config via files or validated config management rather than raw shell exports.
- Validate env vars at process startup (fail fast) instead of at rule-load time.
- Beware: empty rules means default policy — pair env-read failures with a loud audit/metric.
When it happens
Trigger: Calling load_rules() when the policy_rules environment variable contains invalid Unicode (env var set to non-UTF8 bytes) or the OS call to read the environ fails.
Common situations: An env var injected by a container/orchestrator containing raw bytes that are not valid UTF-8; env size limits; process environment corruption; setting the variable via a shell with binary content.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- policy_rules failed to parse
- must not be empty
- cannot contain a platform PATH separator
- AOS_HOME, USERPROFILE, and HOMEDRIVE/HOMEPATH are all unset
- AOS_HOME and HOME are both unset
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/01c56d10cc22c18f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/aos-mcp-broker/src/policy.rs:264
/// Load the invoking principal's rule set from the `policy_rules` `[env]`
/// value. Returns an EMPTY rule set (→ default allow → capability PEP is
/// the live boundary) on any of: unset/empty value, host read error,
/// JSON parse error, or a cap/shape violation — and emits a LOUD audit on
/// the failure paths so an operator monitoring `astrid.v1.audit.policy_*`
/// sees that policy is not in force.
///
/// This degrades to the capability PEP rather than failing CLOSED
/// (deny-all) on a config error, so a malformed rule blob or a transient
/// KV hiccup cannot brick every session. A deployment that wants strict
/// fail-closed on config error is a future hardening knob; the tradeoff
/// is recorded here deliberately.
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();
}
};View on GitHub (pinned to f6f22024fb)