{"record":{"id":"c8a9a90aa91fa2e2","repo":"HKUDS/Vibe-Trading","slug":"display-currency-must-be-usd-or-cny","errorCode":null,"errorMessage":"display_currency must be USD or CNY","messagePattern":"display_currency must be USD or CNY","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/portfolio/config.py","lineNumber":148,"sourceCode":") -> PortfolioSettings:\n    \"\"\"Validate untrusted Web settings against the local connection registry.\n\n    Args:\n        payload: Raw settings dict from the Web UI, CLI or a settings file.\n        connection_store: Local connection registry; a default store is used\n            when omitted.\n\n    Returns:\n        Validated, order-normalized settings.\n\n    Raises:\n        ValueError: If the display currency, the source list, a connection id,\n            a label, or a referenced profile's eligibility is invalid.\n    \"\"\"\n    store = connection_store or ConnectionStore()\n    currency = str(payload.get(\"display_currency\") or \"USD\").strip().upper()\n    if currency not in {\"USD\", \"CNY\"}:\n        raise ValueError(\"display_currency must be USD or CNY\")\n\n    raw_sources = payload.get(\"sources\")\n    if not isinstance(raw_sources, list):\n        raise ValueError(\"sources must be a list\")\n    if len(raw_sources) > 50:\n        raise ValueError(\"at most 50 portfolio sources are allowed\")\n\n    seen_ids: set[str] = set()\n    sources: list[PortfolioSource] = []\n    for index, raw in enumerate(raw_sources):\n        if not isinstance(raw, dict):\n            raise ValueError(\"each portfolio source must be an object\")\n        connection_id = (\n            str(raw.get(\"connection_id\") or raw.get(\"id\") or \"\").strip().lower()\n        )\n        if not _SOURCE_ID_RE.fullmatch(connection_id):\n            raise ValueError(f\"invalid portfolio connection id: {connection_id or '?'}\")\n        legacy_profile_id = str(raw.get(\"profile_id\") or \"\").strip().lower()","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/portfolio/config.py#L130-L166","documentation":"PortfolioSettings parsing rejects display_currency values other than USD or CNY (case-insensitive after strip+upper). The display currency drives all reporting/FX conversion, so only these two are supported.","triggerScenarios":"parse_settings({'display_currency': 'EUR'}) or 'usd ' works but 'eur', 'yen', '' after normalization to non-USD/CNY fails; loading a settings file with an unsupported currency via load().","commonSituations":"Hand-edited portfolio settings JSON, users in other locales assuming arbitrary ISO codes are supported, or currency keys copied from a different config schema.","solutions":["Set display_currency to 'USD' or 'CNY' (any case; it is normalized)","Omit the field entirely — it defaults to USD","Extend the allowed set only if you also implement the required FX conversion"],"exampleFix":"# before\n{\"display_currency\": \"EUR\"}\n# after\n{\"display_currency\": \"USD\"}","handlingStrategy":"validation","validationCode":"currency = str(payload.get('display_currency') or 'USD').strip().upper()\nif currency not in {'USD', 'CNY'}:\n    payload['display_currency'] = 'USD'  # or surface an error to the user","typeGuard":"def is_supported_currency(c) -> bool:\n    return isinstance(c, str) and c.strip().upper() in {'USD', 'CNY'}","tryCatchPattern":"try:\n    settings = store.load()\nexcept ValueError as exc:\n    if 'display_currency' in str(exc):\n        payload['display_currency'] = 'USD'\n        settings = store.parse_settings(payload, store.connection_store)","preventionTips":["Offer only USD/CNY in currency pickers","Default the field to USD rather than letting users invent values","Validate edited settings files with a schema checker before load"],"tags":["python","validation","currency","config"],"backgroundTag":"invalid-config-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}