{"record":{"id":"0140aaf20aecf631","repo":"headroomlabs-ai/headroom","slug":"max-sessions-must-be-0","errorCode":null,"errorMessage":"max_sessions must be > 0","messagePattern":"max_sessions must be > 0","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/proxy/ccr_session_tracker.py","lineNumber":14,"sourceCode":"\"\"\"Session-scoped state for sticky CCR retrieval tool injection.\"\"\"\n\nfrom __future__ import annotations\n\nimport threading\nfrom collections import OrderedDict\n\n\nclass SessionCcrTracker:\n    \"\"\"Bounded LRU tracker recording per-provider/session CCR state.\"\"\"\n\n    def __init__(self, max_sessions: int) -> None:\n        if max_sessions <= 0:\n            raise ValueError(\"max_sessions must be > 0\")\n        self._max_sessions = max_sessions\n        self._lock = threading.RLock()\n        self._sessions: OrderedDict[tuple[str, str], tuple[bool, bytes | None]] = OrderedDict()\n\n    @property\n    def active_sessions(self) -> int:\n        with self._lock:\n            return len(self._sessions)\n\n    def _key(self, provider: str, session_id: str) -> tuple[str, str]:\n        return (provider, session_id)\n\n    def has_done_ccr(self, provider: str, session_id: str) -> bool:\n        \"\"\"Return True when this session has previously performed CCR.\"\"\"\n\n        if not provider:\n            raise ValueError(\"provider must be non-empty\")\n        if not session_id:","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/proxy/ccr_session_tracker.py#L1-L32","documentation":"SessionCcrTracker is a bounded LRU keyed by (provider, session_id) that records which sessions have already done context-clone reuse (CCR). Its constructor validates max_sessions > 0 because an OrderedDict-based bound of 0 or negative would evict every entry immediately or misbehave. This is a direct-constructor guard; from configuration the value normally arrives via resolve_beta_tracker_max_sessions() (see the HEADROOM_BETA_TRACKER_MAX_SESSIONS errors).","triggerScenarios":"Calling SessionCcrTracker(max_sessions=0) or with a negative int in code or tests — typically when computing the bound from a config value, len() of an empty collection, or a subtraction that underflows.","commonSituations":"Test fixtures passing 0 to keep the tracker 'off'; deriving max_sessions from another quantity (e.g. max_total - reserved) that can legitimately reach 0; wiring an env-configured value straight into the constructor without the resolver's validation.","solutions":["Pass a positive bound: SessionCcrTracker(max_sessions=1000).","If the value is computed, clamp or validate it before construction: max(1, computed).","Route user-supplied values through resolve_beta_tracker_max_sessions() so they get the same validation and default."],"exampleFix":"# before\ntracker = SessionCcrTracker(max_sessions=0)\n\n# after\ntracker = SessionCcrTracker(max_sessions=1)  # minimum valid bound","handlingStrategy":"validation","validationCode":"def make_tracker(max_sessions: int | None) -> SessionCcrTracker:\n    return SessionCcrTracker(max_sessions=1000 if not max_sessions or max_sessions <= 0 else max_sessions)","typeGuard":"def valid_bound(value: object) -> bool:\n    return isinstance(value, int) and value > 0","tryCatchPattern":"try:\n    tracker = SessionCcrTracker(max_sessions=bound)\nexcept ValueError:\n    bound = 1000\n    tracker = SessionCcrTracker(max_sessions=bound)  # log the substitution","preventionTips":["Validate numeric config at the edges of your system (CLI/env parse), not at object construction deep in libraries.","Property-test constructors with generated ints to catch boundary assumptions."],"tags":["validation","constructor","lru","python"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}