BerriAI/litellm · error · ValueError

classifier_llm_config.classification_rubric and system_promp

Error message

classifier_llm_config.classification_rubric and system_prompt are mutually exclusive: system_prompt replaces the built-in rubric the preset would select. Drop one.

What it means

Config validator on ComplexityRouterConfig: both a classification_rubric preset and a custom system_prompt are set. The system_prompt silently replaces the rubric the preset would choose, so the ambiguous configuration is rejected — keep one.

Source

Thrown at litellm/router_strategy/complexity_router/config.py:338

    @field_validator("system_prompt")
    @classmethod
    def _reject_blank_system_prompt(cls, value: str | None) -> str | None:
        # A blank string is a misconfiguration, not a request for the default: it would send an
        # empty system role and leave the classifier with no rubric at all. None means default.
        if value is not None and not value.strip():
            raise ValueError("classifier_llm_config.system_prompt must be non-empty; omit it to use the default rubric")
        return value

    @model_validator(mode="after")
    def _reject_rubric_with_system_prompt(self) -> "ClassifierLLMConfig":
        # A custom prompt is the classifier's whole system role, so a preset set alongside it would never
        # reach the wire. Rejecting it beats honoring one of two settings the operator asked for.
        #
        # None, not model_fields_set, is what marks the preset unchosen: this model is dumped and
        # re-validated in place (see /auto_router/test_routing), and a dump re-states every field, so
        # keying on fields_set would reject on the second pass what it accepted on the first.
        if self.system_prompt is not None and self.classification_rubric is not None:
            raise ValueError(
                "classifier_llm_config.classification_rubric and system_prompt are mutually exclusive: system_prompt replaces "
                "the built-in rubric the preset would select. Drop one."
            )
        return self


class ComplexityRouterConfig(BaseModel):
    """Configuration for the ComplexityRouter."""

    # string = pin; list = random pick when adaptive=False, soft-floor home pool when adaptive=True
    tiers: dict[str, str | list[str]] = Field(
        default_factory=lambda: DEFAULT_TIER_MODELS.copy(),
        description=(
            "Mapping of complexity tiers to a model or model pool. "
            "A list is randomly picked from when adaptive=False, and used as a soft-floor home pool when adaptive=True"
        ),
    )

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Drop either classification_rubric or system_prompt from classifier_llm_config; they are mutually exclusive.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at litellm/router_strategy/complexity_router/config.py:338 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/1dafdb48140c6ad0. Report an issue: GitHub.