headroomlabs-ai/headroom · error · ValueError
session_id must be non-empty
Error message
session_id must be non-empty
What it means
The second guard in SessionCcrTracker.has_done_ccr(): provider was non-empty but session_id is the empty string. An empty session key would make every anonymous request share one LRU entry, corrupting the 'has this session already done CCR' signal. The check is a cheap precondition, not an I/O failure.
Source
Thrown at headroom/proxy/ccr_session_tracker.py:33
self._max_sessions = max_sessions
self._lock = threading.RLock()
self._sessions: OrderedDict[tuple[str, str], tuple[bool, bytes | None]] = OrderedDict()
@property
def active_sessions(self) -> int:
with self._lock:
return len(self._sessions)
def _key(self, provider: str, session_id: str) -> tuple[str, str]:
return (provider, session_id)
def has_done_ccr(self, provider: str, session_id: str) -> bool:
"""Return True when this session has previously performed CCR."""
if not provider:
raise ValueError("provider must be non-empty")
if not session_id:
raise ValueError("session_id must be non-empty")
key = self._key(provider, session_id)
with self._lock:
entry = self._sessions.get(key)
if entry is None:
return False
self._sessions.move_to_end(key)
return entry[0]
def get_golden_tool_bytes(self, provider: str, session_id: str) -> bytes | None:
"""Return recorded golden CCR tool-definition bytes, if any."""
if not provider:
raise ValueError("provider must be non-empty")
if not session_id:
raise ValueError("session_id must be non-empty")
key = self._key(provider, session_id)
with self._lock:
entry = self._sessions.get(key)View on GitHub (pinned to 322425c43b)
Solutions
- Mint a session ID when the inbound one is missing: sid = headers.get('x-headroom-session-id') or uuid4().hex.
- Verify the header name your client sends matches what the extraction code reads.
- Skip the CCR fast-path entirely when no session identity exists rather than calling with an empty key.
Example fix
# before
tracker.has_done_ccr('anthropic', headers.get('x-session-id') or '')
# after
sid = headers.get('x-headroom-session-id') or uuid4().hex
tracker.has_done_ccr('anthropic', sid) Defensive patterns
Strategy: validation
Validate before calling
sid = (headers.get("x-headroom-session-id") or "").strip() or uuid4().hex
assert sid # guaranteed non-empty Type guard
def valid_session_id(sid: object) -> bool:
return isinstance(sid, str) and bool(sid.strip()) Try / catch
try:
done = tracker.has_done_ccr(provider, session_id)
except ValueError:
session_id = uuid4().hex
done = False Prevention
- Mint server-side session IDs for anonymous clients so the key space is never empty.
- Keep a single extraction point for session headers and reuse it across handlers.
When it happens
Trigger: Calling has_done_ccr('anthropic', '') — e.g. the handler extracted a session ID from a header the client didn't send, or a code path defaults the ID to '' before the tracker call.
Common situations: Clients that don't emit a session/conversation header (curl tests, minimal scripts); a header-name change (x-session-id vs x-headroom-session-id) making the lookup return None which is then coerced to ''; refactors that moved session extraction after the tracker call.
Related errors
- provider must be non-empty
- magika inference failed: {0}
- invalid pipeline config TOML: {0}
- recommendations file not found: {0}
- bedrock_eventstream_parse_failed
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/897015d7e31980b7.
Report an issue: GitHub.