headroomlabs-ai/headroom · error · HTTPException

hash required

Error message

hash required

What it means

POST /v1/retrieve requires a JSON body containing a non-empty 'hash' field; missing, null, or empty hash returns HTTP 400 'hash required'. The hash key is the compression marker identifier the LLM received when content was compressed.

Source

Thrown at headroom/proxy/server.py:4603

    @app.post("/v1/retrieve", dependencies=[Depends(_require_loopback)])
    async def ccr_retrieve(request: Request):
        """Retrieve original content from CCR compression cache.

        This is the "Retrieve" part of CCR (Compress-Cache-Retrieve).
        When SmartCrusher compresses tool outputs, the original data is cached.
        LLMs can call this endpoint to get more data if needed.

        Request body:
            hash (str): Hash key from compression marker (required)

        Response:
            {"hash": "...", "original_content": "...", ...}
        """
        data = await request.json()
        hash_key = data.get("hash")

        if not hash_key:
            raise HTTPException(status_code=400, detail="hash required")

        store = get_compression_store()

        entry_status = store.get_entry_status(hash_key, clean_expired=True)
        if entry_status["status"] != "available":
            raise HTTPException(
                status_code=404,
                detail=format_retrieval_miss_detail(entry_status),
            )

        # Retrieval is by hash: always return the full original content.
        entry = store.retrieve(hash_key)
        if entry:
            return {
                "hash": hash_key,
                "original_content": entry.original_content,
                "original_tokens": entry.original_tokens,
                "original_item_count": entry.original_item_count,

View on GitHub (pinned to 322425c43b)

Solutions

  1. Include the exact compression marker hash: {"hash": "<value>"}.
  2. Use /v1/retrieve/tool_call to parse provider tool-call formats automatically.
  3. Validate the marker payload before sending.

Example fix

# before
curl -X POST /v1/retrieve -d '{}'

# after
curl -X POST /v1/retrieve -H 'Content-Type: application/json' -d '{"hash": "abc123"}'
Defensive patterns

Strategy: validation

Validate before calling

payload = {"hash": marker_hash}
if not isinstance(marker_hash, str) or not marker_hash:
    raise ValueError("marker must carry a non-empty hash")

Type guard

def has_hash(payload: dict) -> bool:
    return bool(isinstance(payload.get("hash"), str) and payload["hash"].strip())

Try / catch

resp = await client.post("/v1/retrieve", json=payload)
if resp.status_code == 400:
    raise RuntimeError(f"bad retrieval request: {resp.text}")

Prevention

When it happens

Trigger: Posting {} to /v1/retrieve, or a body where 'hash' is null, empty string, or 0.

Common situations: Agent frameworks hand-rolling tool-call bodies instead of using the provided tool-call endpoint; malformed JSON field names like 'hash_key'; LLM omitting the parameter.

Related errors


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