{"record":{"id":"7900860dbe4e29e7","repo":"headroomlabs-ai/headroom","slug":"model-limit-is-required-provide-it-via-kwargs-or","errorCode":null,"errorMessage":"model_limit is required. Provide it via kwargs or configure model_context_limits in HeadroomClient.","messagePattern":"model_limit is required\\. Provide it via kwargs or configure model_context_limits in HeadroomClient\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/transforms/pipeline.py","lineNumber":267,"sourceCode":"                - request_id: Optional request ID for diff artifact.\n                - waste_messages: Optional richer conversion of the same request\n                  used for waste-signal detection only (never transformed).\n\n        Returns:\n            Combined TransformResult.\n        \"\"\"\n        record_metrics = kwargs.pop(\"record_metrics\", True)\n        waste_messages = kwargs.pop(\"waste_messages\", None)\n        waste_signal_token_limit = int(\n            kwargs.pop(\"waste_signal_token_limit\", MAX_WASTE_SIGNAL_DETECTION_TOKENS)\n        )\n        tokenizer = self._get_tokenizer(model)\n        provider_name = self._provider_name()\n\n        # Get model limit from kwargs (should be set by client)\n        model_limit = kwargs.get(\"model_limit\")\n        if model_limit is None:\n            raise ValueError(\n                \"model_limit is required. Provide it via kwargs or \"\n                \"configure model_context_limits in HeadroomClient.\"\n            )\n\n        # Start with original tokens\n        # Circuit breaker open — pass through untouched (issue #847).\n        if self._breaker_is_open():\n            passthrough_tokens = tokenizer.count_messages(messages)\n            return TransformResult(\n                messages=messages,\n                tokens_before=passthrough_tokens,\n                tokens_after=passthrough_tokens,\n                transforms_applied=[\"pipeline:circuit_open\"],\n            )\n\n        t_count = time.perf_counter()\n        tokens_before = tokenizer.count_messages(messages)\n        count_ms = (time.perf_counter() - t_count) * 1000","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/transforms/pipeline.py#L249-L285","documentation":"Raised by the pipeline's transform entry point when `model_limit` is not present in kwargs. The pipeline needs the model's context window size to make budget decisions, and it deliberately does not guess: no limit means no safe compression math. Normal callers (HeadroomClient) inject it from the `model_context_limits` config; calling the pipeline directly without it is the error.","triggerScenarios":"Calling `pipeline.transform(messages, model=...)` (or `run`/equivalent) directly without `model_limit=...` in kwargs, while the wrapping HeadroomClient has no entry for that model in `model_context_limits`.","commonSituations":"Using a new/unlisted model name (e.g. a freshly released or self-hosted model) with no `model_context_limits` entry; bypassing HeadroomClient in scripts or tests and calling the pipeline directly; a client upgrade that changed how limits are resolved.","solutions":["Pass the limit explicitly: `pipeline.transform(messages, model=..., model_limit=200000)`","Configure the limit once in the client: `HeadroomClient(model_context_limits={\"my-model\": 200000})` so every call is injected automatically","If calling from custom code, mirror what HeadroomClient does — resolve the limit from your config and forward it in kwargs"],"exampleFix":"# before\nresult = pipeline.transform(messages, model=\"my-model\")\n\n# after\nclient = HeadroomClient(model_context_limits={\"my-model\": 128000})\nresult = client.pipeline.transform(messages, model=\"my-model\")  # model_limit injected\n# or directly:\nresult = pipeline.transform(messages, model=\"my-model\", model_limit=128000)","handlingStrategy":"validation","validationCode":"MODEL_LIMITS = {\"gpt-4o\": 128000, \"claude-3-5\": 200000}\n\ndef limit_for(model: str) -> int:\n    limit = MODEL_LIMITS.get(model)\n    if limit is None:\n        raise ValueError(f\"no context limit configured for {model!r}; add it to MODEL_LIMITS\")\n    return limit\n\nresult = pipeline.transform(messages, model=model, model_limit=limit_for(model))","typeGuard":"def has_model_limit(kwargs: dict) -> bool:\n    return isinstance(kwargs.get(\"model_limit\"), int) and kwargs[\"model_limit\"] > 0","tryCatchPattern":"try:\n    result = pipeline.transform(messages, model=model)\nexcept ValueError as e:\n    if \"model_limit is required\" in str(e):\n        result = pipeline.transform(messages, model=model, model_limit=MODEL_LIMITS[model])\n    else:\n        raise","preventionTips":["Always route calls through HeadroomClient configured with model_context_limits instead of calling pipeline.transform directly","Add new model names to model_context_limits as part of the rollout checklist for any model upgrade","Fail fast at app startup: verify every model your app uses has a configured limit"],"tags":["configuration","pipeline","model-limits","precondition"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}