{"record":{"id":"59c10695e745d675","repo":"HKUDS/Vibe-Trading","slug":"profile-must-be-paper-live-readonly-or-live-59c106","errorCode":null,"errorMessage":"profile must be 'paper', 'live-readonly' or 'live'","messagePattern":"profile must be 'paper', 'live-readonly' or 'live'","errorType":"validation","errorClass":"TigerConfigError","httpStatus":null,"severity":"error","filePath":"agent/src/trading/connectors/tiger/sdk.py","lineNumber":87,"sourceCode":"        profile: ``paper``, ``live-readonly`` or ``live``.\n        timeout: Network timeout in seconds.\n        readonly: Always true for this layer; order methods are not exposed.\n    \"\"\"\n\n    tiger_id: str = \"\"\n    private_key_path: str = \"\"\n    account: str = \"\"\n    profile: str = \"paper\"\n    timeout: float = 15.0\n    readonly: bool = True\n\n    @classmethod\n    def from_mapping(cls, data: Mapping[str, Any] | None = None) -> \"TigerConfig\":\n        \"\"\"Build a config from a JSON-like mapping, normalizing the profile.\"\"\"\n        payload = dict(data or {})\n        profile = str(payload.get(\"profile\") or \"paper\").strip().lower()\n        if profile not in PROFILE_ENVIRONMENTS:\n            raise TigerConfigError(\"profile must be 'paper', 'live-readonly' or 'live'\")\n        return cls(\n            tiger_id=str(payload.get(\"tiger_id\") or \"\").strip(),\n            private_key_path=str(payload.get(\"private_key_path\") or \"\").strip(),\n            account=str(payload.get(\"account\") or \"\").strip(),\n            profile=profile,\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        tiger_id: str | None = None,\n        private_key_path: str | None = None,\n        account: str | None = None,\n        profile: str | None = None,\n    ) -> \"TigerConfig\":\n        \"\"\"Return a copy with CLI/tool overrides applied.\"\"\"","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connectors/tiger/sdk.py#L69-L105","documentation":"TigerConfig.from_mapping validates the 'profile' key and rejects any value not in PROFILE_ENVIRONMENTS after normalization (strip + lowercase). Because profile defaults to 'paper' only when absent/empty, an explicitly misspelled profile string raises TigerConfigError at config-parse time, before any Tiger API call is made.","triggerScenarios":"Calling TigerConfig.from_mapping (directly or via with_overrides, build_config, load_config) with a mapping whose 'profile' is e.g. 'Paper ', 'LIVE', 'prod', 'simulation', or any non-empty string outside {'paper','live-readonly','live'}. Note whitespace and case are normalized, so only genuinely unknown values fail.","commonSituations":"Hand-edited JSON config with 'profile': 'demo' or 'production'; tooling writing 'live_readonly' instead of 'live-readonly'; copy-pasting profile names from Tiger docs that use different terminology.","solutions":["Set the profile to one of the exact allowed values: 'paper', 'live-readonly', or 'live'","If you intended the default, remove the profile key entirely (it defaults to 'paper')","Fix typo variants like 'live_readonly' -> 'live-readonly' (hyphen, not underscore)"],"exampleFix":"// before\n{\"profile\": \"live_readonly\", \"tiger_id\": \"...\"}\n\n// after\n{\"profile\": \"live-readonly\", \"tiger_id\": \"...\"}","handlingStrategy":"validation","validationCode":"ALLOWED = {'paper', 'live-readonly', 'live'}\n\nprofile = str(data.get('profile') or 'paper').strip().lower()\nassert profile in ALLOWED, f\"bad profile: {profile!r}\"\ncfg = TigerConfig.from_mapping(data)","typeGuard":"def is_valid_tiger_profile(value: object) -> bool:\n    return isinstance(value, str) and value.strip().lower() in {'paper', 'live-readonly', 'live'}","tryCatchPattern":"try:\n    cfg = TigerConfig.from_mapping(raw)\nexcept TigerConfigError as exc:\n    if 'profile' in str(exc):\n        raw['profile'] = 'paper'  # or prompt the user\n        cfg = TigerConfig.from_mapping(raw)\n    else:\n        raise","preventionTips":["Validate profile with a shared constant/enum instead of free-form strings","Generate config files via save_config rather than editing JSON by hand","Add a schema check (e.g. JSON Schema enum) in CI for committed config files"],"tags":["tiger","config","validation","profile"],"backgroundTag":"config-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}