{"record":{"id":"01b7f7fdc9bee191","repo":"headroomlabs-ai/headroom","slug":"invalid-rollout-worker-snapshot","errorCode":null,"errorMessage":"invalid rollout worker snapshot","messagePattern":"invalid rollout worker snapshot","errorType":"exception","errorClass":"RolloutConfigurationError","httpStatus":null,"severity":"error","filePath":"headroom/rollout.py","lineNumber":289,"sourceCode":"        return {\n            \"schema_version\": self.schema_version,\n            \"policy_version\": self.policy_version,\n            \"registry_digest\": self.registry_digest,\n            \"snapshot_digest\": self.snapshot_digest,\n            \"channel\": self.channel.value,\n            \"unsafe_allow_unstable\": self.unsafe_allow_unstable,\n            \"explicit_requested\": sorted(self.config.explicit_requested),\n            \"explicit_disabled\": sorted(self.config.explicit_disabled),\n            \"legacy_requested\": sorted(self.config.legacy_requested),\n            \"legacy_disabled\": sorted(self.config.legacy_disabled),\n        }\n\n    @classmethod\n    def from_internal_dict(cls, value: Mapping[str, object]) -> RolloutSnapshot:\n        \"\"\"Validate and restore a snapshot serialized for worker handoff.\"\"\"\n\n        if not isinstance(value, Mapping):\n            raise RolloutConfigurationError(\"invalid rollout worker snapshot\")\n        try:\n            if value.get(\"schema_version\") != ROLLOUT_SCHEMA_VERSION:\n                raise RolloutConfigurationError(\"unsupported rollout worker schema version\")\n            if value.get(\"policy_version\") != ROLLOUT_POLICY_VERSION:\n                raise RolloutConfigurationError(\"rollout worker policy version mismatch\")\n            channel = RolloutChannel.parse(str(value[\"channel\"]), strict=True)\n            unsafe = value[\"unsafe_allow_unstable\"]\n            if not isinstance(unsafe, bool):\n                raise RolloutConfigurationError(\"invalid rollout worker unsafe override\")\n\n            def names(field: str) -> set[str]:\n                raw = value[field]\n                if not isinstance(raw, list) or not all(isinstance(item, str) for item in raw):\n                    raise RolloutConfigurationError(f\"invalid rollout worker field {field!r}\")\n                return set(_validate_names(set(raw), source=field, strict=True))\n\n            snapshot = _resolve_snapshot(\n                channel=channel,","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/rollout.py#L271-L307","documentation":"Raised by RolloutSnapshot.from_internal_dict() when the value passed to restore a worker-handoff snapshot is not a Mapping at all. This is the coarsest guard: it rejects non-dict payloads (str, list, None) before any field validation; later guards produce more specific messages.","triggerScenarios":"Calling from_internal_dict('encoded-snapshot'), from_internal_dict(None), or passing a JSON string that was never json.loads()-ed, or double-encoded JSON.","commonSituations":"Forgetting to deserialize a JSON payload before restore; passing raw bytes or a queue message body; double-serialization when a worker framework auto-encodes dicts to strings.","solutions":["Pass the already-deserialized dict: from_internal_dict(json.loads(payload)).","Inspect for double encoding — if the value is a str, json.loads it once, then retry.","Type-check at the boundary that hands the snapshot to the worker."],"exampleFix":"# before\nsnapshot = RolloutSnapshot.from_internal_dict(raw_body)  # raw_body is str\n\n# after\nimport json\nsnapshot = RolloutSnapshot.from_internal_dict(json.loads(raw_body))","handlingStrategy":"validation","validationCode":"from collections.abc import Mapping\nimport json\n\nif isinstance(payload, (str, bytes)):\n    payload = json.loads(payload)\nif not isinstance(payload, Mapping):\n    raise ValueError(f'snapshot payload must be a mapping, got {type(payload).__name__}')\nsnapshot = RolloutSnapshot.from_internal_dict(payload)","typeGuard":"from collections.abc import Mapping\n\ndef is_snapshot_mapping(value: object) -> bool:\n    return isinstance(value, Mapping)","tryCatchPattern":"from headroom.rollout import RolloutConfigurationError\n\ntry:\n    snapshot = RolloutSnapshot.from_internal_dict(payload)\nexcept RolloutConfigurationError as e:\n    logger.error('worker snapshot rejected: %s', e)\n    request_fresh_snapshot()  # re-handoff instead of retrying bad payload","preventionTips":["json.loads() once at the queue boundary; never pass raw message bodies to restore.","Type-check the payload shape at the producer before enqueueing.","Log the payload type on failure to catch double-encoding quickly."],"tags":["serialization","rollout","validation","worker-handoff"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}