{"record":{"id":"da874ad4d7b58662","repo":"BerriAI/litellm","slug":"unknown-pattern-type-pattern-config-pattern-type","errorCode":null,"errorMessage":"Unknown pattern_type: {pattern_config.pattern_type}","messagePattern":"Unknown pattern_type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py","lineNumber":748,"sourceCode":"\n        Args:\n            pattern_config: ContentFilterPattern configuration\n        \"\"\"\n        try:\n            extra_config: _PatternExtraLookup = {\"keyword_pattern\": None, \"allow_word_numbers\": False}\n            if pattern_config.pattern_type == \"prebuilt\":\n                if not pattern_config.pattern_name:\n                    raise ValueError(\"pattern_name is required for prebuilt patterns\")\n                compiled = get_compiled_pattern(pattern_config.pattern_name)\n                pattern_name = pattern_config.pattern_name\n                extra_config = self._lookup_pattern_extra(pattern_name)\n            elif pattern_config.pattern_type == \"regex\":\n                if not pattern_config.pattern:\n                    raise ValueError(\"pattern is required for regex patterns\")\n                compiled = re.compile(pattern_config.pattern, re.IGNORECASE)\n                pattern_name = pattern_config.name or \"custom_regex\"\n            else:\n                raise ValueError(f\"Unknown pattern_type: {pattern_config.pattern_type}\")\n\n            keyword_pattern: Final = extra_config[\"keyword_pattern\"]\n            keyword_regex: Final = re.compile(keyword_pattern, re.IGNORECASE) if keyword_pattern else None\n\n            self.compiled_patterns.append(\n                {\n                    \"regex\": compiled,\n                    \"pattern_name\": pattern_name,\n                    \"action\": pattern_config.action,\n                    \"keyword_regex\": keyword_regex,\n                    \"allow_word_numbers\": extra_config[\"allow_word_numbers\"],\n                }\n            )\n            verbose_proxy_logger.debug(\"Added pattern: %s with action %s\", pattern_name, pattern_config.action)\n        except Exception as e:\n            verbose_proxy_logger.error(\"Error adding pattern %s: %s\", pattern_config, e)\n            raise\n","sourceCodeStart":730,"sourceCodeEnd":766,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/guardrails/guardrail_hooks/litellm_content_filter/content_filter.py#L730-L766","documentation":"ValueError raised in _add_pattern when a patterns[] entry's pattern_type is neither the literal \"prebuilt\" nor \"regex\". The dispatcher matches those two strings exactly (case-sensitive), so any other value — including different casing like \"Regex\" or invented types like \"keyword\", \"builtin\" — falls into the else branch and is rejected.","triggerScenarios":"Config yaml has a patterns entry with a misspelled or unsupported pattern_type, e.g. {pattern_type: keyword, keyword: '...'} or {pattern_type: Prebuilt, pattern_name: ssn}; _add_pattern hits the else branch during initialization.","commonSituations":"Typo or wrong casing in pattern_type; assumption that more pattern types exist (keyword, builtin, llm); config migrated from another tool with different type names.","solutions":["Set pattern_type to exactly 'prebuilt' or 'regex' (lowercase).","For keyword-style blocking, use pattern_type: regex with a word-boundary regex, or the guardrail's blocked_words/blocked_words_file mechanism instead.","Add a config lint that validates pattern_type against the allowed literal set before deploy."],"exampleFix":"# before\npatterns:\n  - pattern_type: Keyword\n    pattern_name: ssn\n    action: BLOCK\n\n# after\npatterns:\n  - pattern_type: prebuilt\n    pattern_name: ssn\n    action: BLOCK","handlingStrategy":"type-guard","validationCode":"# Lint pattern_type against the closed set the dispatcher accepts\nALLOWED_PATTERN_TYPES = {\"prebuilt\", \"regex\"}\n\ndef lint_pattern_types(patterns: list[dict]) -> list[str]:\n    return [\n        f\"unknown pattern_type {p.get('pattern_type')!r}: must be one of {sorted(ALLOWED_PATTERN_TYPES)} — {p}\"\n        for p in patterns\n        if p.get(\"pattern_type\") not in ALLOWED_PATTERN_TYPES\n    ]","typeGuard":"from typing import Literal, TypedDict\n\nPatternType = Literal[\"prebuilt\", \"regex\"]\n\nclass PatternConfig(TypedDict):\n    pattern_type: PatternType\n    action: str\n    pattern_name: str | None\n    pattern: str | None\n    name: str | None\n\ndef narrow_pattern_type(value: str) -> PatternType | None:\n    \"\"\"Return the value only if the dispatcher accepts it (exact, lowercase).\"\"\"\n    return value if value in (\"prebuilt\", \"regex\") else None","tryCatchPattern":null,"preventionTips":["pattern_type is matched exactly and case-sensitively: only 'prebuilt' and 'regex'.","For keyword blocking use blocked_words / blocked_words_file — there is no 'keyword' pattern_type.","Run the pattern-type lint in CI so typos fail the build, not proxy startup."],"tags":["configuration","validation","content-filter","enum"],"backgroundTag":"invalid-config-value","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}