{"record":{"id":"7d620c9c418055f2","repo":"HKUDS/Vibe-Trading","slug":"invalid-risk-tier-req-risk-tier","errorCode":null,"errorMessage":"invalid risk_tier: {req.risk_tier}","messagePattern":"invalid risk_tier: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"agent/src/api/sessions_routes.py","lineNumber":455,"sourceCode":"        \"/sessions/{session_id}/goal\",\n        response_model=GoalSnapshotResponse,\n        status_code=status.HTTP_201_CREATED,\n        dependencies=[Depends(require_auth)],\n    )\n    async def create_session_goal(session_id: str, req: CreateGoalRequest):\n        \"\"\"Create or replace the current finance research goal for a session.\"\"\"\n        _host_validate_path_param(session_id, \"session_id\")\n        svc, _session = _get_existing_session_or_404(session_id)\n        from src.goal import RiskTier\n        from src.goal.context import default_goal_criteria\n\n        criteria = [item.strip() for item in req.criteria if item.strip()]\n        if not criteria:\n            criteria = default_goal_criteria()\n        try:\n            risk_tier = RiskTier(req.risk_tier)\n        except ValueError as exc:\n            raise HTTPException(status_code=400, detail=f\"invalid risk_tier: {req.risk_tier}\") from exc\n        if risk_tier is RiskTier.LIVE_TRADING_OR_EXECUTION:\n            raise HTTPException(status_code=400, detail=\"live trading or execution goals are not supported\")\n\n        goal_store = _get_goal_store()\n        try:\n            goal = goal_store.replace_goal(\n                session_id=session_id,\n                objective=req.objective,\n                criteria=criteria,\n                ui_summary=req.ui_summary,\n                source=\"api\",\n                protocol=req.protocol,\n                risk_tier=risk_tier,\n                token_budget=req.token_budget,\n                turn_budget=req.turn_budget,\n                time_budget_seconds=req.time_budget_seconds,\n            )\n        except ValueError as exc:","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/api/sessions_routes.py#L437-L473","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use one of the exact RiskTier enum values accepted by the server (inspect the RiskTier enum in agent source or the API schema)","Validate risk_tier on the client before sending (enum membership check)","Upgrade the client to match the server version's enum if values changed","Send the value with exact casing/spelling required by the enum"],"exampleFix":"# before\napi.create_session_goal(sid, objective=\"...\", risk_tier=\"high\")  # 400\n\n# after\nrisk_tier=\"LOW_RISK\"  # exact RiskTier member, e.g. one of the enum's defined names\napi.create_session_goal(sid, objective=\"...\", risk_tier=risk_tier)","handlingStrategy":"type-guard","validationCode":"from agent.goals import RiskTier  # or fetch allowed values from OpenAPI schema\nALLOWED = {t.value for t in RiskTier}\nassert req.risk_tier in ALLOWED, f\"risk_tier must be one of {sorted(ALLOWED)}\"","typeGuard":"from typing import Literal\nRiskTierName = Literal[\"LOW_RISK\", \"MEDIUM_RISK\", \"HIGH_RISK\"]  # mirror server enum\n\ndef is_valid_risk_tier(v: str) -> TypeGuard[RiskTierName]:\n    return v in (\"LOW_RISK\", \"MEDIUM_RISK\", \"HIGH_RISK\")","tryCatchPattern":"try:\n    goal = api.create_session_goal(sid, payload)\nexcept HTTPError as e:\n    if e.response.status_code == 400 and \"risk_tier\" in e.response.text:\n        raise ValueError(f\"Bad risk_tier {payload['risk_tier']!r}; allowed: {sorted(ALLOWED)}\") from e\n    raise","preventionTips":["Derive the accepted enum set from the server's OpenAPI/RiskTier definition","Use closed enum types (Literal/enum class) in client models, not free strings","Add contract tests that fail when server enum values change"],"tags":["validation","enum","http-400","goals","risk-tier"],"backgroundTag":"enum-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}