mudler/LocalAI · error
router/score: at least one policy is required
Error message
router/score: at least one policy is required
What it means
Construction-time panic in NewScoreClassifier (token-based score classifier): the policies slice is empty. Like the rerank classifier, score policies define the labels candidates are built from via buildCandidate(label, stopToken); with none there is nothing to score.
Source
Thrown at core/services/routing/router/score.go:167
// stablePrefix is the rendered-prompt prefix shared by every probe:
// the chat template's preamble plus the option-list system prompt,
// up to where the per-turn text begins. Computed once (the byte-wise
// common prefix of two synthetic probes) and sent with each Score
// call as a state-reuse boundary hint — on backends whose models
// cannot rewind state (hybrid/recurrent), a snapshot at this
// boundary is what keeps repeat scoring at probe-size cost instead
// of a full option-list re-prefill.
stablePrefixOnce sync.Once
stablePrefix string
}
// NewScoreClassifier panics on caller errors at construction (empty
// policies, missing description, nil scorer) — same rationale as the
// other classifiers. See ScoreClassifierOptions for the optional
// knobs and their zero-value defaults.
func NewScoreClassifier(policies []ScorePolicy, scorer backend.Scorer, opts ScoreClassifierOptions) *ScoreClassifier {
if len(policies) == 0 {
panic("router/score: at least one policy is required")
}
if scorer == nil {
panic("router/score: scorer is required (configure router.classifier_model)")
}
for _, p := range policies {
if p.Label == "" {
panic("router/score: policy has empty label")
}
if p.Description == "" {
panic(fmt.Sprintf("router/score: policy %q has no description", p.Label))
}
}
labels := make([]string, 0, len(policies))
for _, p := range policies {
labels = append(labels, p.Label)
}
if opts.ActivationThreshold <= 0 {
opts.ActivationThreshold = defaultActivationThresholdView on GitHub (pinned to 44413a9d06)
Solutions
- Add one or more policies (label + description) under the score classifier config
- Verify YAML nesting places policies inside the classifier block
- In Go callers, skip classifier construction when policies is empty rather than calling the constructor
Example fix
# before (yaml)
router:
classifier:
type: score
policies: []
# after
router:
classifier:
type: score
policies:
- label: chat
description: "general conversation" Defensive patterns
Strategy: validation
Validate before calling
if len(cfg.Router.Classifier.Policies) == 0 {
return fmt.Errorf("router: score classifier requires at least one policy")
} Type guard
func hasPolicies(p []ScorePolicy) bool { return len(p) > 0 } Try / catch
defer func() { if r := recover(); r != nil { log.Printf("router init failed: %v", r) } }() Prevention
- Validate the whole classifier config block before construction
- Refuse to enable the router when its policies list is empty
- Test config parsing for each classifier type
When it happens
Trigger: Configuring a score-type router classifier without a policies list; passing an empty slice programmatically; a config loader filtering out all policies (e.g. due to per-entry validation failures) before construction.
Common situations: Switching classifier type from rerank to score and forgetting to carry policies over; indentation errors detaching the policies block; scaffolding config from a template with the policies section commented out.
Related errors
- router/rerank: at least one policy is required
- router/rerank: policy has empty label
- router/rerank: policy %q has no description
- router/score: policy has empty label
- router/score: policy %q has no description
AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15).
Data as JSON: /api/errors/61dcece42ce738df.
Report an issue: GitHub.