{"record":{"id":"f6522988224c9808","repo":"HKUDS/Vibe-Trading","slug":"portfolio-connection-ids-must-be-unique","errorCode":null,"errorMessage":"portfolio connection ids must be unique","messagePattern":"portfolio connection ids must be unique","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/portfolio/config.py","lineNumber":182,"sourceCode":"        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()\n        if legacy_profile_id:\n            legacy_profile = profile_by_id(legacy_profile_id)\n            connection = store.ensure(\n                connection_id,\n                legacy_profile.id,\n                str(raw.get(\"label\") or legacy_profile.label),\n            )\n        else:\n            connection = store.get(connection_id)\n        profile = profile_by_id(connection.profile_id)\n        if profile not in eligible_profiles():\n            raise ValueError(\n                f\"connection is not eligible for read-only portfolios: {connection_id}\"\n            )\n        if connection_id in seen_ids:\n            raise ValueError(\"portfolio connection ids must be unique\")\n        label = str(raw.get(\"label\") or connection.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                \"portfolio source labels must contain 1 to 80 printable characters\"\n            )\n        seen_ids.add(connection_id)\n        sources.append(\n            PortfolioSource(\n                connection_id=connection_id,\n                label=label,\n                enabled=bool(raw.get(\"enabled\", True)),\n                order=int(raw.get(\"order\", index)),\n                include_cash=bool(raw.get(\"include_cash\", True)),\n            )","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/portfolio/config.py#L164-L200","documentation":"Portfolio settings reject duplicate connection ids across the sources array; a seen_ids set tracks each id and the second occurrence raises before it can be appended. Uniqueness prevents double-counting the same account in aggregation.","triggerScenarios":"The same connection_id appears in two source entries — e.g. 'binance-main' listed once with a custom label and once without, commonly after merging two settings files.","commonSituations":"Concatenating configs, adding a source that already exists with a different label, or copy-paste duplication inside the JSON array.","solutions":["Deduplicate the sources array by connection_id (keep one entry per connection)","If you need two views of one connection, create a second distinct connection id instead","Validate uniqueness before saving the file"],"exampleFix":"python - <<'PY'\nimport json\np = json.load(open('portfolio.json'))\nseen = set(); p['sources'] = [s for s in p['sources'] if not (s.get('connection_id') or s.get('id')) in seen and not seen.add(s.get('connection_id') or s.get('id'))]\njson.dump(p, open('portfolio.json','w'), indent=2)\nPY","handlingStrategy":"validation","validationCode":"seen = set(); unique = []\nfor s in payload['sources']:\n    cid = (s.get('connection_id') or s.get('id'))\n    if cid not in seen:\n        seen.add(cid); unique.append(s)\npayload['sources'] = unique","typeGuard":"def sources_are_unique(payload) -> bool:\n    ids = [(s.get('connection_id') or s.get('id')) for s in payload['sources']]\n    return len(ids) == len(set(ids))","tryCatchPattern":"try:\n    settings = parse_settings(payload, store)\nexcept ValueError as exc:\n    if 'must be unique' in str(exc):\n        payload['sources'] = dedupe_by_id(payload['sources'])\n        settings = parse_settings(payload, store)","preventionTips":["Deduplicate by connection_id whenever merging config files","Add a uniqueness check to config linters/CI validation","Prefer editing one canonical source of truth over concatenating files"],"tags":["python","config","uniqueness","duplicates"],"backgroundTag":"duplicate-config-entry","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}