{"record":{"id":"15ec8e118574504e","repo":"HKUDS/Vibe-Trading","slug":"connection-profile-is-not-eligible-for-read-only-p","errorCode":null,"errorMessage":"connection profile is not eligible for read-only portfolios: {profile_id}","messagePattern":"connection profile is not eligible for read-only portfolios: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/trading/connections.py","lineNumber":310,"sourceCode":"            raw: Decoded registry row.\n\n        Returns:\n            The validated connection.\n\n        Raises:\n            ValueError: If the row is not an object, carries an invalid id or\n                label, names an unknown or ineligible profile, or claims a\n                credential reference that does not match its transport.\n        \"\"\"\n        if not isinstance(raw, dict):\n            raise ValueError(\"each local connection must be an object\")\n        connection_id = str(raw.get(\"id\") or \"\").strip().lower()\n        if not _ID_RE.fullmatch(connection_id):\n            raise ValueError(f\"invalid local connection id: {connection_id or '?'}\")\n        profile_id = str(raw.get(\"profile_id\") or \"\").strip().lower()\n        profile = profile_by_id(profile_id)\n        if not is_portfolio_connection_profile(profile):\n            raise ValueError(\n                f\"connection profile is not eligible for read-only portfolios: {profile_id}\"\n            )\n        label = str(raw.get(\"label\") or profile.label).strip()\n        if (\n            not label\n            or len(label) > 80\n            or any(ord(character) < 32 for character in label)\n        ):\n            raise ValueError(\n                \"connection label must contain 1 to 80 printable characters\"\n            )\n        expected_ref = _credential_reference(profile.id, connection_id)\n        credential_ref = str(raw.get(\"credential_ref\") or expected_ref)\n        if (\n            credential_ref == CredentialStore.reference(connection_id)\n            and profile.transport != \"local_plugin\"\n        ):\n            credential_ref = expected_ref","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/trading/connections.py#L292-L328","documentation":"Raised when a stored connection references a profile that either does not exist (profile_by_id returned nothing) or exists but is not marked as eligible for read-only portfolio connections (is_portfolio_connection_profile is false). Only whitelisted read-only-capable profiles may back a local connection.","triggerScenarios":"A settings entry with profile_id that is misspelled, refers to a removed/renamed profile, or names a profile type that is not portfolio-eligible (e.g. a write/trading-only connector profile) is parsed by _parse during list() or save().","commonSituations":"Upgrading the agent after a profile was renamed or removed so old settings files reference dead ids; typos in profile_id; trying to attach a non-read-only connector profile to a local portfolio connection.","solutions":["Check the registered profile list and correct profile_id to a valid, portfolio-eligible profile id","If the profile was renamed in an upgrade, update the settings entry to the new id (or recreate the connection)","Remove the stale connection entry and recreate it via store.create() with a known-good profile","Verify profile_by_id(profile_id) and is_portfolio_connection_profile(...) in a REPL before persisting"],"exampleFix":"// before\n{\"id\": \"alpaca\", \"profile_id\": \"alpaca-pro\"}\n\n// after\n{\"id\": \"alpaca\", \"profile_id\": \"paper\"}","handlingStrategy":"validation","validationCode":"from trading.profiles import profile_by_id, is_portfolio_connection_profile\nprofile = profile_by_id(candidate_profile_id)\nif not is_portfolio_connection_profile(profile):\n    raise ValueError(f\"pick a portfolio-eligible profile, not {candidate_profile_id}\")","typeGuard":"def is_portfolio_profile_id(profile_id: str) -> bool:\n    return is_portfolio_connection_profile(profile_by_id(profile_id.strip().lower()))","tryCatchPattern":"try:\n    store.list()\nexcept ValueError as exc:\n    if \"not eligible\" in str(exc):\n        # drop or re-point the offending connection entry\n        ...","preventionTips":["Expose only portfolio-eligible profiles in connection-creation UIs","Run a settings-migration step after upgrades that renames/removes profiles","Fail fast at connection-creation time instead of at settings-load time"],"tags":["python","configuration","profile-validation","trading"],"backgroundTag":"unknown-profile-referenced","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}