headroomlabs-ai/headroom · error · ValueError

provider must be non-empty

Error message

provider must be non-empty

What it means

SessionCcrTracker.has_done_ccr(provider, session_id) requires both key components to be non-empty strings; an empty provider would create a ('', session_id) LRU entry that collides across all providers and defeats the per-provider isolation the tracker is built for. The guard fires before any dict access, so no state is mutated on failure.

Source

Thrown at headroom/proxy/ccr_session_tracker.py:31

        if max_sessions <= 0:
            raise ValueError("max_sessions must be > 0")
        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)

View on GitHub (pinned to 322425c43b)

Solutions

  1. Resolve a real provider name before querying — log the model/route that produced an empty provider.
  2. Generate or require a session ID at the boundary: if the client sends none, mint a UUID per connection instead of passing ''.
  3. In tests, use literal non-empty values like ('anthropic', 'test-session').

Example fix

# before
tracker.has_done_ccr(provider_name, request.session_id or '')

# after
sid = request.session_id or uuid4().hex
tracker.has_done_ccr(provider_name or 'unknown', sid)
Defensive patterns

Strategy: validation

Validate before calling

def tracker_key_ok(provider: str, session_id: str) -> bool:
    return bool(provider) and bool(session_id)

Type guard

def has_identity(provider: str | None, session_id: str | None) -> TypeGuard[tuple[str, str]]:
    return bool(provider) and bool(session_id)

Try / catch

try:
    done = tracker.has_done_ccr(provider, session_id)
except ValueError as exc:
    log.error("missing identity for CCR lookup: %s", exc)
    done = False  # safe default: treat as not-done

Prevention

When it happens

Trigger: Calling has_done_ccr('', 'sess-1') or has_done_ccr('anthropic', '') — typically because an upstream request arrived with no provider resolved (unknown model routing) or no session identifier (client sent no session header/ID).

Common situations: A client that omits the session header entirely; a provider name derived from a model string that failed to map; passing None coerced to '' by an earlier str() conversion; calling the tracker directly in tests with placeholder empty strings.

Related errors


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