{"record":{"id":"2c29d58ffaab0b5b","repo":"zylon-ai/private-gpt","slug":"reasoning-effort-must-be-a-reasoningeffort-string","errorCode":null,"errorMessage":"reasoning_effort must be a ReasoningEffort, string, or None; got {type(reasoning_effort).__name__}","messagePattern":"reasoning_effort must be a ReasoningEffort, string, or None; got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/llm/models.py","lineNumber":34,"sourceCode":"            return cls(effort_str)\n        raise ValueError(f\"Unknown reasoning effort level: {effort_str}\")\n\n    @property\n    def is_thinking_enabled(self) -> bool:\n        return self != ReasoningEffort.NONE\n\n\ndef normalize_reasoning_effort(\n    reasoning_effort: ReasoningEffort | str | None,\n) -> ReasoningEffort:\n    \"\"\"Normalize values crossing untyped or serialized LLM boundaries.\"\"\"\n    if reasoning_effort is None:\n        return ReasoningEffort.NONE\n    if isinstance(reasoning_effort, ReasoningEffort):\n        return reasoning_effort\n    if isinstance(reasoning_effort, str):\n        return ReasoningEffort.from_str(reasoning_effort)\n    raise TypeError(\n        \"reasoning_effort must be a ReasoningEffort, string, or None; \"\n        f\"got {type(reasoning_effort).__name__}\"\n    )\n\n\ndef _get_exception_types() -> tuple[type[BaseException], ...]:\n    base_exceptions = (ConnectionError, TimeoutError, OSError)\n\n    try:\n        from grpc.aio import AioRpcError  # ty:ignore[unresolved-import]\n        from tritonclient.utils import (  # ty:ignore[unresolved-import]\n            InferenceServerException,\n        )\n\n        return *base_exceptions, AioRpcError, InferenceServerException\n    except ImportError:\n        return base_exceptions\n","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/llm/models.py#L16-L52","documentation":"TypeError from normalize_reasoning_effort: the value crossing an untyped/serialized boundary is not None, not a ReasoningEffort, and not a str — e.g. an int, dict, or list. The function exists precisely to normalize values coming from serialized LLM payloads; only None/str/enum are acceptable, everything else is a type error rather than a coercion.","triggerScenarios":"Passing reasoning_effort as a non-string: an int (e.g. 2 from an API that numeric-codes effort), a dict from parsed JSON like {'effort': 'high'}, or a list. Happens when request payloads or DB rows are forwarded without field-level validation.","commonSituations":"REST handlers forwarding body fields verbatim; dataclass/pydantic models typing the field as Any; values deserialized from JSON where the effort was nested or numeric.","solutions":["Ensure the value is a string, ReasoningEffort, or None before calling; extract nested fields first (payload['effort'] not payload).","Type the field as ReasoningEffort | str | None in request models so validation happens at parse time.","For numeric codes, map them to the string levels before calling."],"exampleFix":"# before\neffort = normalize_reasoning_effort(request_body)  # dict -> TypeError\n\n# after\neffort = normalize_reasoning_effort(request_body.get(\"effort\"))","handlingStrategy":"type-guard","validationCode":"def is_normalizable_effort(value: object) -> bool:\n    return value is None or isinstance(value, (str, ReasoningEffort))","typeGuard":"from private_gpt.components.llm.models import ReasoningEffort\n\ndef is_normalizable_effort(value: object) -> bool:\n    return value is None or isinstance(value, (str, ReasoningEffort))","tryCatchPattern":"try:\n    effort = normalize_reasoning_effort(value)\nexcept TypeError:\n    log.warning('Bad reasoning_effort type %s; defaulting to none', type(value).__name__)\n    effort = ReasoningEffort.NONE","preventionTips":["Type the field as ReasoningEffort | str | None in pydantic models crossing API boundaries.","Extract nested fields (payload['effort']) before normalizing; never pass whole dicts.","Add unit tests asserting TypeError for ints/dicts to lock in the contract."],"tags":["type-error","reasoning","validation","serialization"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}