{"record":{"id":"79bd0df4e938b78c","repo":"mudler/LocalAI","slug":"router-score-policy-has-empty-label","errorCode":null,"errorMessage":"router/score: policy has empty label","messagePattern":"router/score: policy has empty label","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/services/routing/router/score.go","lineNumber":174,"sourceCode":"\t// of a full option-list re-prefill.\n\tstablePrefixOnce sync.Once\n\tstablePrefix     string\n}\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}","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/core/services/routing/router/score.go#L156-L192","documentation":"Construction-time panic in NewScoreClassifier: a ScorePolicy entry has an empty Label. Labels become the scored candidates (wrapped by buildCandidate) and the routing decision values, so an empty label breaks both scoring and dispatch.","triggerScenarios":"A policies entry missing or blanking its label field; a zero-value ScorePolicy appended in Go; YAML key spelled differently (name instead of label).","commonSituations":"Hand-written policy lists where one block lost its label line; schema drift between router classifier types using different field names; config generated from a spreadsheet/CSV with an empty first column.","solutions":["Give every policy a non-empty, unique label","Check the field name is exactly label","Validate the policies slice (labels and descriptions non-empty) at config load time"],"exampleFix":"# before (yaml)\npolicies:\n  - description: \"general conversation\"\n# after\npolicies:\n  - label: chat\n    description: \"general conversation\"","handlingStrategy":"validation","validationCode":"for i, p := range policies {\n    if strings.TrimSpace(p.Label) == \"\" {\n        return fmt.Errorf(\"policy %d: empty label\", i)\n    }\n}","typeGuard":"func validLabels(ps []ScorePolicy) bool { for _, p := range ps { if p.Label == \"\" { return false } }; return true }","tryCatchPattern":null,"preventionTips":["Use a strict config schema requiring label on every policy","Fail config load with the policy index on missing fields","Avoid hand-editing long policy lists without a lint pass"],"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"}