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

  1. Check how POLICY_RULES_ENV is set; unset and re-set it with valid UTF-8 JSON content.
  2. Inspect the value with `env | grep policy_rules` or `locale`-aware tools; replace binary/invalid bytes.
  3. If you intend no rules, unset the variable entirely so load_rules takes the Ok(None)/empty path.
  4. 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

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


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)