{"record":{"id":"a96155b66412cb76","repo":"HKUDS/Vibe-Trading","slug":"profile-must-be-paper-live-readonly-or-live-a96155","errorCode":null,"errorMessage":"profile must be 'paper', 'live-readonly' or 'live'","messagePattern":"profile must be 'paper', 'live-readonly' or 'live'","errorType":"validation","errorClass":"FutuConfigError","httpStatus":null,"severity":"error","filePath":"agent/src/trading/connectors/futu/sdk.py","lineNumber":110,"sourceCode":"    readonly: bool = True\n\n    @classmethod\n    def from_mapping(cls, data: Mapping[str, Any] | None = None) -> \"FutuConfig\":\n        \"\"\"Build a config from a JSON-like mapping, normalizing the profile.\n\n        Args:\n            data: Mapping with any subset of config fields.\n\n        Returns:\n            A normalized :class:`FutuConfig`.\n\n        Raises:\n            FutuConfigError: If the profile is not a recognized value.\n        \"\"\"\n        payload = dict(data or {})\n        profile = str(payload.get(\"profile\") or \"paper\").strip().lower()\n        if profile not in PROFILE_ENVIRONMENTS:\n            raise FutuConfigError(\"profile must be 'paper', 'live-readonly' or 'live'\")\n        return cls(\n            host=str(payload.get(\"host\") or DEFAULT_HOST).strip(),\n            port=int(payload.get(\"port\") or DEFAULT_PORT),\n            profile=profile,\n            security_firm=str(payload.get(\"security_firm\") or \"FUTUSECURITIES\").strip().upper(),\n            filter_trdmarket=str(payload.get(\"filter_trdmarket\") or \"HK\").strip().upper(),\n            acc_id=int(payload.get(\"acc_id\") or 0),\n            timeout=float(payload.get(\"timeout\") or 15.0),\n            readonly=bool(payload.get(\"readonly\", True)),\n        )\n\n    def with_overrides(\n        self,\n        *,\n        host: str | None = None,\n        port: int | None = None,\n        profile: str | None = None,\n        security_firm: str | None = None,","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/futu/sdk.py#L92-L128","documentation":"Raised by FutuConfig.from_mapping when the 'profile' key is not one of 'paper', 'live-readonly', or 'live' (after strip/lower; empty defaults to 'paper').","triggerScenarios":"from_mapping({'profile': 'demo'}) or {'profile': 'LIVE_READ'}; config file with a mistyped profile name.","commonSituations":"Typos in futu config JSON ('real', 'prod', 'simulation'), stale profile names from older library versions, copy-paste from other brokers' configs.","solutions":["Set profile to exactly 'paper', 'live-readonly', or 'live'","Check for trailing spaces/case issues — values are normalized, so fix genuine typos"],"exampleFix":"// before\n{\"profile\": \"prod\"}\n// after\n{\"profile\": \"live\"}","handlingStrategy":"validation","validationCode":"PROFILES = {'paper', 'live-readonly', 'live'}\nassert cfg_dict.get('profile', 'paper') in PROFILES","typeGuard":"def is_valid_futu_profile(p: str | None) -> bool:\n    return (p or 'paper').strip().lower() in {'paper','live-readonly','live'}","tryCatchPattern":null,"preventionTips":["Offer profile as a dropdown, not free text","Add a config lint step that validates profile names at startup"],"tags":["futu","config","profile","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}