{"record":{"id":"b29f6d78ad3fc23f","repo":"headroomlabs-ai/headroom","slug":"unknown-scorer-tier-tier-valid-tiers-valid-t","errorCode":null,"errorMessage":"Unknown scorer tier: {tier}. Valid tiers: {valid_tiers}","messagePattern":"Unknown scorer tier: (.+?)\\. Valid tiers: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/relevance/__init__.py","lineNumber":124,"sourceCode":"    tier = tier.lower()\n\n    if tier == \"bm25\":\n        return BM25Scorer(**kwargs)\n\n    elif tier == \"embedding\":\n        if not EmbeddingScorer.is_available():\n            raise RuntimeError(\n                \"EmbeddingScorer requires sentence-transformers. \"\n                \"Install with: pip install headroom[relevance]\"\n            )\n        return EmbeddingScorer(**kwargs)\n\n    elif tier == \"hybrid\":\n        return HybridScorer(**kwargs)\n\n    else:\n        valid_tiers = [\"bm25\", \"embedding\", \"hybrid\"]\n        raise ValueError(f\"Unknown scorer tier: {tier}. Valid tiers: {valid_tiers}\")\n","sourceCodeStart":106,"sourceCodeEnd":125,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/relevance/__init__.py#L106-L125","documentation":"Raised by create_scorer() when the tier argument does not match 'bm25', 'embedding', or 'hybrid' (tiers are lowercased before comparison, so case is not the issue). It is a plain argument-validation error listing the valid tiers; typos and unsupported aliases are the usual cause.","triggerScenarios":"Calling create_scorer('vector'), create_scorer('embeddings'), create_scorer('BM25 ') with trailing content, or passing a None/default from an unset config field.","commonSituations":"Config drift between your app's tier names and the library's; renamed tiers across versions; empty string from a missing config key.","solutions":["Use one of the documented tiers: 'bm25', 'embedding', or 'hybrid'.","Whitelist the tier in your config schema before passing it through.","Default missing config values to 'bm25' (the dependency-free tier)."],"exampleFix":"# before\nscorer = create_scorer(config.get('tier', ''))\n\n# after\nscorer = create_scorer(config.get('tier') or 'bm25')","handlingStrategy":"validation","validationCode":"VALID_TIERS = {'bm25', 'embedding', 'hybrid'}\ntier = (config.get('tier') or 'bm25').lower()\nif tier not in VALID_TIERS:\n    raise ConfigError(f'tier must be one of {sorted(VALID_TIERS)}, got {config.get(\"tier\")!r}')\nscorer = create_scorer(tier)","typeGuard":"def is_scorer_tier(tier: str) -> bool:\n    return isinstance(tier, str) and tier.lower() in {'bm25', 'embedding', 'hybrid'}","tryCatchPattern":"try:\n    scorer = create_scorer(tier)\nexcept ValueError as e:\n    raise ConfigError(str(e)) from e  # surface to config validation layer","preventionTips":["Constrain the tier field in your config schema to the three allowed values.","Default unset tier config to 'bm25'.","Add an allowlist test that fails when library tiers change across upgrades."],"tags":["validation","arguments","relevance"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}