{"record":{"id":"25a4d6e7c56638b5","repo":"mudler/LocalAI","slug":"router-score-policy-q-has-no-description","errorCode":null,"errorMessage":"router/score: policy %q has no description","messagePattern":"router/score: policy %q has no description","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/services/routing/router/score.go","lineNumber":177,"sourceCode":"}\n\n// NewScoreClassifier panics on caller errors at construction (empty\n// policies, missing description, nil scorer) — same rationale as the\n// other classifiers. See ScoreClassifierOptions for the optional\n// knobs and their zero-value defaults.\nfunc NewScoreClassifier(policies []ScorePolicy, scorer backend.Scorer, opts ScoreClassifierOptions) *ScoreClassifier {\n\tif len(policies) == 0 {\n\t\tpanic(\"router/score: at least one policy is required\")\n\t}\n\tif scorer == nil {\n\t\tpanic(\"router/score: scorer is required (configure router.classifier_model)\")\n\t}\n\tfor _, p := range policies {\n\t\tif p.Label == \"\" {\n\t\t\tpanic(\"router/score: policy has empty label\")\n\t\t}\n\t\tif p.Description == \"\" {\n\t\t\tpanic(fmt.Sprintf(\"router/score: policy %q has no description\", p.Label))\n\t\t}\n\t}\n\tlabels := make([]string, 0, len(policies))\n\tfor _, p := range policies {\n\t\tlabels = append(labels, p.Label)\n\t}\n\tif opts.ActivationThreshold <= 0 {\n\t\topts.ActivationThreshold = defaultActivationThreshold\n\t}\n\tif opts.StopToken == \"\" {\n\t\topts.StopToken = defaultStopToken\n\t}\n\tif opts.PromptRenderer == nil {\n\t\topts.PromptRenderer = chatMLRenderer\n\t}\n\tswitch opts.Normalization {\n\tcase \"\", ScoreNormalizationRaw:\n\t\topts.Normalization = ScoreNormalizationRaw","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/core/services/routing/router/score.go#L159-L195","documentation":"Construction-time panic in NewScoreClassifier: a policy has a label but an empty Description. Descriptions feed the system prompt rendered by renderSystemPrompt and give the scorer context to discriminate labels; an empty one makes the policy unusable, so construction aborts with the offending label quoted.","triggerScenarios":"A policies entry with label only; description key present but empty/templating resolves to ''; programmatic ScorePolicy with Description unset.","commonSituations":"Truncated example configs; CI config tests that fill labels programmatically but skip descriptions; belief that description is optional documentation rather than scoring input.","solutions":["Write a discriminative description for each policy","Audit all entries for both label and description","Add a pre-flight config lint that reports the specific policy missing a description"],"exampleFix":"# before (yaml)\npolicies:\n  - label: chat\n# after\npolicies:\n  - label: chat\n    description: \"general conversation and Q&A\"","handlingStrategy":"validation","validationCode":"for i, p := range policies {\n    if strings.TrimSpace(p.Description) == \"\" {\n        return fmt.Errorf(\"policy %q: empty description\", p.Label)\n    }\n}","typeGuard":"func validDescriptions(ps []ScorePolicy) bool { for _, p := range ps { if p.Description == \"\" { return false } }; return true }","tryCatchPattern":null,"preventionTips":["Require descriptions in config linting","Write discriminative descriptions up front; empty ones are useless to the scorer anyway","Copy from complete examples"],"tags":["router","config","validation","panic"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}