ZhuLinsen/daily_stock_analysis · error · AgentBackendConfigError

capability_unsupported

capability_unsupported

Error message

Unsupported AGENT_BACKEND: {requested}

What it means

resolve_agent_backend_id validates config.agent_backend against the allowed set {auto, litellm, codex_app_server}; anything else raises AgentBackendConfigError with code 'capability_unsupported'. 'auto' resolves to litellm. The error is a structured ValueError carrying a machine-readable code for API layers to map to HTTP responses.

Source

Thrown at src/agent/agent_backend.py:50

        "unknown_backend_error",
    }
)
AGENT_BACKEND_IDS = frozenset({"auto", "litellm", "codex_app_server"})


class AgentBackendConfigError(ValueError):
    """Structured Agent backend selection error."""

    def __init__(self, code: str, message: str) -> None:
        super().__init__(message)
        self.code = code


def resolve_agent_backend_id(config: Any) -> str:
    """Resolve Chat backend; ``auto`` deliberately remains LiteLLM."""
    requested = str(getattr(config, "agent_backend", "auto") or "auto").strip().lower()
    if requested not in AGENT_BACKEND_IDS:
        raise AgentBackendConfigError(
            "capability_unsupported",
            f"Unsupported AGENT_BACKEND: {requested}",
        )
    return "litellm" if requested == "auto" else requested


@dataclass(frozen=True)
class AgentRunRequest:
    system_prompt: str
    history_messages: List[Dict[str, Any]]
    user_message: str
    session_id: str
    stock_scope: Optional[StockScope]
    max_steps: int
    max_wall_clock_seconds: Optional[float]
    progress_callback: Optional[Callable[[Dict[str, Any]], None]] = None
    cancel_event: Optional[threading.Event] = None

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Set AGENT_BACKEND to one of: auto, litellm, or codex_app_server (or unset it — default is auto/litellm).
  2. If you intended the Codex path, fix the spelling to exactly codex_app_server.
  3. Catch AgentBackendConfigError at the API boundary and inspect .code == 'capability_unsupported' to return a 4xx with the allowed values, instead of a generic 500.
  4. If you are adding a new backend, register its id in AGENT_BACKEND_IDS (src/agent/agent_backend.py:35) rather than bypassing the check.

Example fix

# before
# .env
AGENT_BACKEND=codex   # -> capability_unsupported

# after
# .env
AGENT_BACKEND=codex_app_server
Defensive patterns

Strategy: type-guard

Validate before calling

from src.agent.agent_backend import AGENT_BACKEND_IDS

requested = (config.agent_backend or "auto").strip().lower()
assert requested in AGENT_BACKEND_IDS, f"AGENT_BACKEND must be one of {sorted(AGENT_BACKEND_IDS)}"

Type guard

def agent_backend_valid(value: str) -> bool:
    return (value or "auto").strip().lower() in AGENT_BACKEND_IDS  # {'auto','litellm','codex_app_server'}

Try / catch

from src.agent.agent_backend import AgentBackendConfigError

try:
    backend_id = resolve_agent_backend_id(config)
except AgentBackendConfigError as e:
    if e.code == "capability_unsupported":
        return JSONResponse(status_code=400, content={"error": str(e), "allowed": sorted(AGENT_BACKEND_IDS)})
    raise

Prevention

When it happens

Trigger: Setting AGENT_BACKEND to an unsupported value such as 'openai', 'codex', 'codex-agent', or 'codex_appserver' (the codex value is 'codex_app_server', with underscores); whitespace/case are tolerated (.strip().lower()) but typos are not; empty string or None falls back to 'auto' safely.

Common situations: New deployment copying an env template with a stale backend name; users guessing 'codex' instead of 'codex_app_server'; API callers passing an arbitrary string through config construction without an enum check.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/d5f53b9c9352068c. Report an issue: GitHub.