{"record":{"id":"a9498cdafb251779","repo":"mudler/LocalAI","slug":"router-score-scorer-is-required-configure-router","errorCode":null,"errorMessage":"router/score: scorer is required (configure router.classifier_model)","messagePattern":"router/score: scorer is required \\(configure router\\.classifier_model\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/services/routing/router/score.go","lineNumber":170,"sourceCode":"\t// common prefix of two synthetic probes) and sent with each Score\n\t// call as a state-reuse boundary hint — on backends whose models\n\t// cannot rewind state (hybrid/recurrent), a snapshot at this\n\t// boundary is what keeps repeat scoring at probe-size cost instead\n\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","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/mudler/LocalAI/blob/44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26/core/services/routing/router/score.go#L152-L188","documentation":"Construction-time panic in NewScoreClassifier: the scorer backend handle is nil. The scorer (configured via router.classifier_model) is the model whose logprobs the classifier reads to score each label candidate; nil means no scoring backend exists, so the classifier cannot work.","triggerScenarios":"router.classifier_model unset or pointing at a model that failed to load/resolution returned nil; calling NewScoreClassifier(policies, nil, opts) directly; model registry not yet populated when the router is constructed.","commonSituations":"Enabling the score router without a classifier model installed; classifier_model typo; referencing a chat model without logprob support as the scorer; startup ordering where the router builds before backends register.","solutions":["Set router.classifier_model to an installed, score-capable model","Confirm the model loads (check startup logs / model list)","Ensure the chosen backend implements backend.Scorer (exposes token logprobs)","If constructing programmatically, resolve the scorer and fail with a clear error before calling the constructor"],"exampleFix":"# before (yaml)\nrouter:\n  classifier:\n    type: score\n    policies: [...]\n# after\nrouter:\n  classifier_model: classifier-model\n  classifier:\n    type: score\n    policies: [...]","handlingStrategy":"validation","validationCode":"scorer, err := resolveModel(cfg.Router.ClassifierModel)\nif err != nil || scorer == nil {\n    return fmt.Errorf(\"router: classifier_model %q not loaded\", cfg.Router.ClassifierModel)\n}","typeGuard":"func implementsScorer(m backend.Backend) bool { _, ok := m.(backend.Scorer); return ok }","tryCatchPattern":null,"preventionTips":["Ensure classifier_model is installed and logprob-capable","Type-assert backend.Scorer at assembly time with a clear error","Order startup so models resolve before the router builds"],"tags":["router","config","nil","classifier"],"backgroundTag":null,"analyzedSha":"44413a9d06bf5bc52ce088ba8ca74e5a2e8bee26","analyzedAt":"2026-08-15T10:13:50.291Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}