BerriAI/litellm · error · ValueError

classifier_llm_config.system_prompt must be non-empty; omit

Error message

classifier_llm_config.system_prompt must be non-empty; omit it to use the default rubric

What it means

Field validator on the classifier LLM config: system_prompt was set to a whitespace-only string. A blank prompt is a misconfiguration, not a request for the default rubric — pass None to use the built-in rubric.

Source

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

            "neither the default rubric nor the context-window closing line is appended, so the prompt "
            "owns the whole taxonomy and the tier names SIMPLE/MEDIUM/COMPLEX/REASONING become whatever "
            "buckets it defines: a prompt that classifies data sensitivity routes on that instead of on "
            "difficulty. Two consequences of full replacement. The default rubric's closing paragraph is "
            "the classifier's prompt-injection defense, telling it that the caller's quoted system prompt "
            "and prior turns are material to judge and never instructions; a replacement that omits it "
            "lets a caller ask for a tier and get it. And the heuristic fallback still scores complexity, "
            "so a router on some other taxonomy wants classifier_fallback='default_model'. Leave unset "
            "for the built-in rubric. Only applies when classifier_type is 'llm'."
        ),
    )

    @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

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Provide a non-empty system_prompt or omit it to use the default rubric.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at litellm/router_strategy/complexity_router/config.py:326 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/f10a21ec709e1b7b. Report an issue: GitHub.