{"record":{"id":"a60f45e9cfe636cd","repo":"headroomlabs-ai/headroom","slug":"invalid-tool-tracker-max-sessions-env-normalize","errorCode":null,"errorMessage":"Invalid {TOOL_TRACKER_MAX_SESSIONS_ENV}={normalized!r}; expected positive int","messagePattern":"Invalid (.+?)=(.+?); expected positive int","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/proxy/tool_injection_policy.py","lineNumber":37,"sourceCode":"    if not normalized:\n        return TOOL_INJECTION_STICKY_DEFAULT\n    if normalized in (\"enabled\", \"disabled\"):\n        return cast(ToolInjectionStickyMode, normalized)\n    raise ValueError(\n        f\"Invalid {TOOL_INJECTION_STICKY_ENV}={normalized!r}; expected 'enabled' or 'disabled'\"\n    )\n\n\ndef resolve_tool_tracker_max_sessions(raw: str | None) -> int:\n    \"\"\"Resolve the positive LRU session bound for tool injection tracking.\"\"\"\n\n    normalized = (raw or \"\").strip()\n    if not normalized:\n        return TOOL_TRACKER_MAX_SESSIONS_DEFAULT\n    try:\n        value = int(normalized)\n    except ValueError as exc:\n        raise ValueError(\n            f\"Invalid {TOOL_TRACKER_MAX_SESSIONS_ENV}={normalized!r}; expected positive int\"\n        ) from exc\n    if value <= 0:\n        raise ValueError(\n            f\"Invalid {TOOL_TRACKER_MAX_SESSIONS_ENV}={normalized!r}; expected positive int\"\n        )\n    return value\n","sourceCodeStart":19,"sourceCodeEnd":45,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/proxy/tool_injection_policy.py#L19-L45","documentation":"Raised by resolve_tool_tracker_max_sessions() when HEADROOM_TOOL_TRACKER_MAX_SESSIONS is set to a string that cannot be parsed as an integer. The value bounds the LRU cache of tool-injection sessions, so garbage input fails fast rather than silently disabling the bound. Empty/unset is fine and returns the default (1000).","triggerScenarios":"Setting HEADROOM_TOOL_TRACKER_MAX_SESSIONS to '1_000', '1e3', '1000.5', 'many', or any non-integer string, then starting the proxy or calling resolve_tool_tracker_max_sessions().","commonSituations":"Using thousands separators or scientific notation in env values; pasting a float; quoting issues leaving stray characters like '1000 ' with a comment appended ('1000 # cap').","solutions":["Set HEADROOM_TOOL_TRACKER_MAX_SESSIONS to a plain integer literal such as '500'.","Unset the variable to use the default of 1000.","Strip any decorations (underscores, units, comments) from the value before it reaches the process."],"exampleFix":"# before\nHEADROOM_TOOL_TRACKER_MAX_SESSIONS=1_000\n\n# after\nHEADROOM_TOOL_TRACKER_MAX_SESSIONS=1000","handlingStrategy":"validation","validationCode":"raw = os.environ.get('HEADROOM_TOOL_TRACKER_MAX_SESSIONS')\nif raw and not raw.strip().lstrip('-').isdigit():\n    raise SystemConfigError(f'HEADROOM_TOOL_TRACKER_MAX_SESSIONS must be an int, got {raw!r}')","typeGuard":"def is_int_string(raw: str | None) -> bool:\n    s = (raw or '').strip()\n    return s == '' or s.lstrip('-').isdigit()","tryCatchPattern":"try:\n    cap = resolve_tool_tracker_max_sessions(raw)\nexcept ValueError as e:\n    raise SystemConfigError(str(e)) from e","preventionTips":["Use plain integer literals in env files — no separators, floats, or inline comments.","Centralize env parsing in one config module validated at startup.","Unit-test your config loader against malformed values."],"tags":["configuration","environment","validation","lru-cache"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}