{"record":{"id":"e175704c40815911","repo":"HKUDS/Vibe-Trading","slug":"invalid-period-exc","errorCode":null,"errorMessage":"invalid period: {exc}","messagePattern":"invalid period: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"agent/src/api/alpha_routes.py","lineNumber":507,"sourceCode":"    # -----------------------------------------------------------------------\n    # POST /alpha/bench\n    # -----------------------------------------------------------------------\n\n    @app.post(\n        \"/alpha/bench\",\n        status_code=202,\n        dependencies=[Depends(require_auth)],\n    )\n    async def kick_off_bench(payload: BenchRequest) -> dict[str, Any]:\n        \"\"\"Queue a background bench job and return a job_id.\"\"\"\n        # Cheap period parse pre-check so we 400 here instead of letting the\n        # worker fail asynchronously.\n        from src.tools.alpha_bench_tool import _parse_period\n\n        try:\n            _parse_period(payload.period)\n        except ValueError as exc:\n            raise HTTPException(status_code=400, detail=f\"invalid period: {exc}\")\n\n        # Concurrency cap. We peek at the semaphore counter rather than\n        # ``acquire(block=False)`` so the actual acquire happens inside the\n        # worker (after the 202 is returned). _value is a CPython\n        # implementation detail but it's been stable since 3.0 and asyncio's\n        # own ``locked()`` uses it.\n        sem = _get_bench_semaphore()\n        # ``locked()`` returns True iff the counter is 0; defensive check.\n        if sem.locked() or getattr(sem, \"_value\", MAX_CONCURRENT_BENCHES) <= 0:\n            raise HTTPException(\n                status_code=429,\n                detail=\"too many running benches; wait for one to finish\",\n            )\n\n        _prune_old_jobs()\n\n        job_id = uuid.uuid4().hex\n        with _JOBS_LOCK:","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/api/alpha_routes.py#L489-L525","documentation":"The limit parameter is coerced with int(value); if that raises TypeError (None) or ValueError ('abc', '1.5', ''), this ValueError is raised. String digits like '60' are accepted, as are floats that truncate cleanly, so the failure is specifically about non-numeric input.","triggerScenarios":"Calling execute(..., limit='fifty'), limit=None, limit='', or limit=[50]. Numeric strings '50' and floats 50.0 succeed; '50.5' raises because int('50.5') fails.","commonSituations":"LLM tool call emitting the schema default as a string word; config/env vars delivering empty strings; passing a pandas/numpy scalar whose str() is not plain digits; upstream form field not coerced to int.","solutions":["Coerce before calling: limit=int(raw or 60)","Whitelist the raw value: use a pydantic/marshmallow IntField or json-schema type integer at the tool boundary","Default missing values explicitly rather than passing None: kwargs.get('limit', 60)"],"exampleFix":"# before\nexecute(action='universe', limit=request.args.get('limit'))  # '' or 'fifty'\n# after\ntry:\n    limit=int(request.args.get('limit', 60))\nexcept (TypeError, ValueError):\n    limit=60\nexecute(action='universe', limit=limit)","handlingStrategy":"validation","validationCode":"try:\n    limit = int(value)\nexcept (TypeError, ValueError):\n    limit = 60  # sensible default\nelse:\n    if not 1 <= limit <= MAX_RESULT_ROWS:\n        limit = min(max(limit, 1), MAX_RESULT_ROWS)","typeGuard":"def is_int_like(v) -> bool:\n    try:\n        int(v); return True\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    tool.execute(action='universe', limit=raw)\nexcept ValueError as e:\n    if 'limit must be an integer' in str(e):\n        result = tool.execute(action='universe', limit=60)\n    else:\n        raise","preventionTips":["Coerce limit to int at the boundary; never pass raw strings/None","Declare limit as JSON schema type integer with default"],"tags":["python","validation","type-coercion"],"backgroundTag":"wrong-argument-type","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}