zylon-ai/private-gpt · error · ValueError

Unknown reasoning effort level: {effort_str}

Error message

Unknown reasoning effort level: {effort_str}

What it means

ValueError from ReasoningEffort.from_str: the lowercased input string is not one of the enum's values (none, low, medium, high, max, xhigh). The enum is the closed vocabulary for reasoning effort across the library; any other string is rejected rather than guessed.

Source

Thrown at private_gpt/components/llm/models.py:17

import enum


class ReasoningEffort(enum.StrEnum):
    NONE = "none"
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    MAX = "max"
    XHIGH = "xhigh"

    @classmethod
    def from_str(cls, effort_str: str) -> "ReasoningEffort":
        effort_str = effort_str.lower()
        if effort_str in cls._value2member_map_:
            return cls(effort_str)
        raise ValueError(f"Unknown reasoning effort level: {effort_str}")

    @property
    def is_thinking_enabled(self) -> bool:
        return self != ReasoningEffort.NONE


def normalize_reasoning_effort(
    reasoning_effort: ReasoningEffort | str | None,
) -> ReasoningEffort:
    """Normalize values crossing untyped or serialized LLM boundaries."""
    if reasoning_effort is None:
        return ReasoningEffort.NONE
    if isinstance(reasoning_effort, ReasoningEffort):
        return reasoning_effort
    if isinstance(reasoning_effort, str):
        return ReasoningEffort.from_str(reasoning_effort)
    raise TypeError(
        "reasoning_effort must be a ReasoningEffort, string, or None; "

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Use one of the exact values: none, low, medium, high, max, xhigh (any case; it is lowercased).
  2. If 'off'/'disabled' was intended, use 'none'.
  3. Validate free-text effort settings against this list at config-load time to fail with a clearer message.

Example fix

# before
reasoning_effort: aggressive

# after
reasoning_effort: high
Defensive patterns

Strategy: type-guard

Validate before calling

VALID_EFFORTS = {"none", "low", "medium", "high", "max", "xhigh"}

def effort_is_valid(s: str) -> bool:
    return s.lower() in VALID_EFFORTS

Type guard

from private_gpt.components.llm.models import ReasoningEffort

def is_reasoning_effort_str(value: object) -> bool:
    return isinstance(value, str) and value.lower() in ReasoningEffort._value2member_map_

Try / catch

try:
    effort = ReasoningEffort.from_str(raw)
except ValueError:
    log.warning('Unknown reasoning effort %r; defaulting to none', raw)
    effort = ReasoningEffort.NONE

Prevention

When it happens

Trigger: Calling from_str with e.g. "OFF", "ultra", "minimal", or a config/env value like 'reasoning_effort: aggressive'; also case is handled (it lowercases) but unknown words are not.

Common situations: Hand-written settings.yaml with an unsupported effort word; values from another provider's API (e.g. OpenAI's 'medium'/'high' subset works, but other vendors' labels like 'aggressive' do not); stale configs from versions before 'max'/'xhigh' existed or after a level was renamed.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/07f9d27f2fa06701. Report an issue: GitHub.