HKUDS/Vibe-Trading · error · HTTPException

invalid risk_tier

Error message

invalid risk_tier: {req.risk_tier}

What it means

When creating a session goal, the request's risk_tier string is converted with RiskTier(req.risk_tier); any value not matching a member of the RiskTier enum raises ValueError, which is re-raised as 400 with the offending value shown. This is enum validation, not business-logic rejection (that's the separate live-trading check).

Solutions

  1. Use one of the exact RiskTier enum values accepted by the server (inspect the RiskTier enum in agent source or the API schema)
  2. Validate risk_tier on the client before sending (enum membership check)
  3. Upgrade the client to match the server version's enum if values changed
  4. Send the value with exact casing/spelling required by the enum

Example fix

# before
api.create_session_goal(sid, objective="...", risk_tier="high")  # 400

# after
risk_tier="LOW_RISK"  # exact RiskTier member, e.g. one of the enum's defined names
api.create_session_goal(sid, objective="...", risk_tier=risk_tier)
Defensive patterns

Strategy: type-guard

Validate before calling

from agent.goals import RiskTier  # or fetch allowed values from OpenAPI schema
ALLOWED = {t.value for t in RiskTier}
assert req.risk_tier in ALLOWED, f"risk_tier must be one of {sorted(ALLOWED)}"

Type guard

from typing import Literal
RiskTierName = Literal["LOW_RISK", "MEDIUM_RISK", "HIGH_RISK"]  # mirror server enum

def is_valid_risk_tier(v: str) -> TypeGuard[RiskTierName]:
    return v in ("LOW_RISK", "MEDIUM_RISK", "HIGH_RISK")

Try / catch

try:
    goal = api.create_session_goal(sid, payload)
except HTTPError as e:
    if e.response.status_code == 400 and "risk_tier" in e.response.text:
        raise ValueError(f"Bad risk_tier {payload['risk_tier']!r}; allowed: {sorted(ALLOWED)}") from e
    raise

Prevention

When it happens

Trigger: POST /sessions/{id}/goal (or PUT replacing the goal) with risk_tier like 'high', 'LIVE', 'medium-risk', an empty string, or any casing/typo not exactly matching a RiskTier member name/value.

Common situations: Client invents its own tier vocabulary instead of the enum's; casing differences (e.g. 'live_trading_or_execution' vs the canonical form); older clients sending tiers removed in a version change; form fields defaulting to '' when untouched.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/7d620c9c418055f2. Report an issue: GitHub.

Appendix: source

Thrown at agent/src/api/sessions_routes.py:455

        "/sessions/{session_id}/goal",
        response_model=GoalSnapshotResponse,
        status_code=status.HTTP_201_CREATED,
        dependencies=[Depends(require_auth)],
    )
    async def create_session_goal(session_id: str, req: CreateGoalRequest):
        """Create or replace the current finance research goal for a session."""
        _host_validate_path_param(session_id, "session_id")
        svc, _session = _get_existing_session_or_404(session_id)
        from src.goal import RiskTier
        from src.goal.context import default_goal_criteria

        criteria = [item.strip() for item in req.criteria if item.strip()]
        if not criteria:
            criteria = default_goal_criteria()
        try:
            risk_tier = RiskTier(req.risk_tier)
        except ValueError as exc:
            raise HTTPException(status_code=400, detail=f"invalid risk_tier: {req.risk_tier}") from exc
        if risk_tier is RiskTier.LIVE_TRADING_OR_EXECUTION:
            raise HTTPException(status_code=400, detail="live trading or execution goals are not supported")

        goal_store = _get_goal_store()
        try:
            goal = goal_store.replace_goal(
                session_id=session_id,
                objective=req.objective,
                criteria=criteria,
                ui_summary=req.ui_summary,
                source="api",
                protocol=req.protocol,
                risk_tier=risk_tier,
                token_budget=req.token_budget,
                turn_budget=req.turn_budget,
                time_budget_seconds=req.time_budget_seconds,
            )
        except ValueError as exc:

View on GitHub (pinned to 80ffdda44c)