{"record":{"id":"ba069a6b93edc885","repo":"HKUDS/Vibe-Trading","slug":"invalid-alpha-id","errorCode":null,"errorMessage":"invalid alpha_id","messagePattern":"invalid alpha_id","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"agent/src/api/alpha_routes.py","lineNumber":456,"sourceCode":"                }\n            )\n        return {\n            \"status\": \"ok\",\n            \"alphas\": alphas,\n            \"total\": total,\n            \"returned\": len(alphas),\n            \"truncated\": total > len(alphas),\n        }\n\n    # -----------------------------------------------------------------------\n    # GET /alpha/{alpha_id}\n    # -----------------------------------------------------------------------\n\n    @app.get(\"/alpha/{alpha_id}\", dependencies=[Depends(require_auth)])\n    async def get_alpha(alpha_id: str) -> dict[str, Any]:\n        \"\"\"Return alpha metadata + the source code of its zoo .py file.\"\"\"\n        if not _ALPHA_ID_RE.fullmatch(alpha_id or \"\"):\n            raise HTTPException(status_code=400, detail=\"invalid alpha_id\")\n\n        from src.factors.registry import RegistryError, get_default_registry\n\n        registry = get_default_registry()\n        try:\n            alpha = registry.get(alpha_id)\n        except KeyError:\n            raise HTTPException(\n                status_code=404,\n                detail={\"status\": \"error\", \"error\": \"alpha_id not found\"},\n            )\n\n        try:\n            source_code = registry.get_source(alpha_id)\n        except RegistryError as exc:\n            # Source-read failure is a degraded but recoverable case — log and\n            # surface a short placeholder. The reason here is a typed registry\n            # error (size cap or OS error from a known path), safe to expose.","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/api/alpha_routes.py#L438-L474","documentation":"The tool caps how many tickers can be queried in one call via MAX_QUERY_STOCKS. If the normalized, deduped stock_ids list exceeds that cap, this ValueError is raised before any SQL runs, protecting the read-only snapshot from oversized queries.","triggerScenarios":"Calling execute(action='latest', stock_ids=[...]) with more than MAX_QUERY_STOCKS entries — e.g. batching an entire index membership (TWSE has 900+ listings) in one request instead of chunking.","commonSituations":"Feeding the output of action='universe' straight into lookup/latest; exporting a full portfolio from a spreadsheet; removing a previously applied chunking loop during refactoring.","solutions":["Chunk the list and loop: for chunk in batched(ids, MAX_QUERY_STOCKS): execute(action=..., stock_ids=chunk)","Reduce the request to only the tickers you actually need","Read MAX_QUERY_STOCKS from the module and size batches dynamically so cap changes don't break you"],"exampleFix":"# before\nexecute(action='latest', stock_ids=all_universe_ids)\n# after\nfrom itertools import islice\ndef chunked(seq, n):\n    it=iter(seq)\n    while (b:=list(islice(it,n))): yield b\nresults=[execute(action='latest', stock_ids=c) for c in chunked(ids, MAX_QUERY_STOCKS)]","handlingStrategy":"validation","validationCode":"from agent.src.tools.taiwan_stock_data_tool import MAX_QUERY_STOCKS\nids = list(dict.fromkeys(ids))  # dedupe, order-preserving\nassert len(ids) <= MAX_QUERY_STOCKS, f'cap is {MAX_QUERY_STOCKS}, got {len(ids)}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Chunk IDs with itertools.islice in size MAX_QUERY_STOCKS","Dedupe before sending — duplicates silently count toward the cap check twice then get removed"],"tags":["python","validation","limit-exceeded","batching"],"backgroundTag":"input-limit-exceeded","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}