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
- 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.