headroomlabs-ai/headroom · error · RolloutConfigurationError

unknown rollout feature(s) in {source}: {', '.join(unknown)}

Error message

unknown rollout feature(s) in {source}: {', '.join(unknown)}; valid: {valid}

What it means

Raised (as RolloutConfigurationError) by _validate_names in headroom/rollout.py when feature names supplied through HEADROOM_FEATURES / HEADROOM_DISABLE_FEATURES environment variables or the requested=/disabled= arguments of resolve_rollout() contain names that are not keys of the FEATURES registry. The message lists the unknown names and the valid set. With strict=True (the snapshot path parses rollout config strictly) it raises; with strict=False it only logs a warning and ignores the unknown names (fail-closed: the feature stays off).

Source

Thrown at headroom/rollout.py:359

                elif _falsey(environ[alias]):
                    legacy_disabled.add(spec.name)
        return _resolve_snapshot(
            channel=self.channel,
            explicit_requested=set(self.config.explicit_requested),
            explicit_disabled=set(self.config.explicit_disabled),
            legacy_requested=legacy_requested,
            legacy_disabled=legacy_disabled,
            unsafe=self.unsafe_allow_unstable,
        )


def _validate_names(names: set[str], *, source: str, strict: bool) -> frozenset[str]:
    unknown = sorted(names - FEATURES.keys())
    if unknown:
        valid = ", ".join(sorted(FEATURES))
        message = f"unknown rollout feature(s) in {source}: {', '.join(unknown)}; valid: {valid}"
        if strict:
            raise RolloutConfigurationError(message)
        logger.warning("%s; ignoring unknown names (fail-closed)", message)
    return frozenset(names & FEATURES.keys())


def resolve_rollout(
    environ: Mapping[str, str] | None = None,
    *,
    requested: Iterable[str] = (),
    disabled: Iterable[str] = (),
    strict: bool = False,
) -> RolloutSnapshot:
    """Resolve all rollout inputs exactly once into an immutable snapshot."""

    env = os.environ if environ is None else environ
    channel = RolloutChannel.parse(env.get("HEADROOM_ROLLOUT_CHANNEL"), strict=strict)
    requested_names = _split_names(env.get("HEADROOM_FEATURES")) | {
        normalized for name in requested if (normalized := name.strip().lower().replace("-", "_"))
    }

View on GitHub (pinned to 322425c43b)

Solutions

  1. Compare the offending names against the valid list in the error message and fix typos/dashes-vs-underscores.
  2. If the feature disappeared, remove it from HEADROOM_FEATURES / HEADROOM_DISABLE_FEATURES or the requested=/disabled= arguments after checking `headroom` docs or FEATURES keys for the current name.
  3. Pin or upgrade to a headroom version whose FEATURES registry contains the names you use.
  4. If you intentionally pass untrusted/user-supplied names, call resolve_rollout(..., strict=False) so unknown names are ignored with a warning instead of raising.

Example fix

# before
HEADROOM_FEATURES=conetxt_packing  # typo, raises RolloutConfigurationError

# after
HEADROOM_FEATURES=context_packing
Defensive patterns

Strategy: validation

Validate before calling

from headroom.rollout import FEATURES, resolve_rollout

names = ['context_packing', 'my_flag']
unknown = [n for n in names if n not in FEATURES]
if unknown:
    raise SystemConfigError(f'unknown features: {unknown}')
snap = resolve_rollout(requested=names)

Type guard

from headroom.rollout import FEATURES

def is_known_feature(name: str) -> bool:
    return name in FEATURES

Try / catch

from headroom.rollout import RolloutConfigurationError
try:
    snap = resolve_rollout(requested=names, strict=True)
except RolloutConfigurationError as e:
    # message already lists valid names; drop unknowns and retry or fail loudly
    raise

Prevention

When it happens

Trigger: Calling resolve_rollout(requested=['feature_that_does_not_exist']) or setting HEADROOM_FEATURES=nonexistent_flag, or a typo like HEADROOM_FEATURES=conetxt_packing where the registry key is 'context_packing'. The snapshot/strict path (line ~304) always uses strict=True, so any persisted rollout config containing a removed or misspelled feature name raises on load.

Common situations: Feature was renamed or removed in a newer headroom version while a stale env var or saved rollout config still names it; CI pipelines that pin HEADROOM_FEATURES from an old runbook; typos in dotenv files.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/077387a06409bdef. Report an issue: GitHub.