{"record":{"id":"34f7a4642a05e5d6","repo":"HKUDS/Vibe-Trading","slug":"mode-must-be-auto-symbol-discover-or-typ","errorCode":null,"errorMessage":"mode must be 'auto', 'symbol', 'discover', or 'type'","messagePattern":"mode must be 'auto', 'symbol', 'discover', or 'type'","errorType":"validation","errorClass":"EtoroAPIError","httpStatus":null,"severity":"warning","filePath":"agent/src/trading/connectors/etoro/instruments.py","lineNumber":192,"sourceCode":"            ``discover`` (fuzzy ``search`` param only), or ``type`` (browse by\n            ``instrument_type_id`` / asset-class alias).\n        instrument_type_id: Optional eToro ``instrumentTypeID`` filter (e.g. ``10``\n            for crypto). When set, uses ``GET /market-data/instruments`` with\n            ``instrumentTypeIds``.\n        include_rates: When browsing by type, attach bid/ask/last from the flat\n            ``/market-data/instruments/rates`` endpoint (works on all profiles).\n    \"\"\"\n    from src.trading.connectors.etoro.client import load_config\n\n    cfg = config or load_config()\n    token = str(query or \"\").strip()\n    if not token:\n        raise EtoroAPIError(\"search query is required\")\n\n    clean_limit = max(1, min(int(limit), 50))\n    clean_mode = str(mode or \"auto\").strip().lower()\n    if clean_mode not in (\"auto\", \"symbol\", \"discover\", \"type\"):\n        raise EtoroAPIError(\"mode must be 'auto', 'symbol', 'discover', or 'type'\")\n\n    if clean_mode == \"type\" or instrument_type_id is not None:\n        resolved_type_id = instrument_type_id\n        if resolved_type_id is None:\n            resolved_type_id = _instrument_type_id_from_query(token, cfg)\n        if resolved_type_id is None:\n            raise EtoroAPIError(\n                \"instrument_type_id is required for type browse \"\n                \"(e.g. 10 for crypto) or use an asset-class query like 'crypto'\"\n            )\n        return list_instruments_by_type(\n            resolved_type_id,\n            cfg,\n            limit=clean_limit,\n            include_rates=include_rates,\n        )\n\n    rows: list[dict[str, Any]] = []","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/etoro/instruments.py#L174-L210","documentation":"Raised by search_instruments when the mode argument is not one of 'auto', 'symbol', 'discover', or 'type' (case-insensitive after strip/lower).","triggerScenarios":"Calling search_instruments('btc', mode='tick') or mode='symbol-match' or any typo like 'Auto ' handled fine but 'aauto' not.","commonSituations":"Typos in mode strings, outdated mode names after a library upgrade, dynamic mode built from user input.","solutions":["Use exactly one of 'auto', 'symbol', 'discover', 'type'","If mode comes from user input, validate against the allowed set before calling"],"exampleFix":"# before\nsearch_instruments('btc', mode='ticker')\n# after\nsearch_instruments('btc', mode='symbol')","handlingStrategy":"validation","validationCode":"VALID_MODES = {'auto', 'symbol', 'discover', 'type'}\nmode = (mode or 'auto').strip().lower()\nassert mode in VALID_MODES, f'mode must be one of {VALID_MODES}'","typeGuard":"def is_valid_mode(mode: str | None) -> bool:\n    return (mode or 'auto').strip().lower() in {'auto','symbol','discover','type'}","tryCatchPattern":null,"preventionTips":["Expose mode as an enum/limited dropdown in your UI","Centralize the allowed-mode set instead of scattering string literals"],"tags":["etoro","validation","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}