HKUDS/Vibe-Trading · error · ValueError
portfolio connection ids must be unique
Error message
portfolio connection ids must be unique
What it means
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.
Source
Thrown at agent/src/portfolio/config.py:182
if not _SOURCE_ID_RE.fullmatch(connection_id):
raise ValueError(f"invalid portfolio connection id: {connection_id or '?'}")
legacy_profile_id = str(raw.get("profile_id") or "").strip().lower()
if legacy_profile_id:
legacy_profile = profile_by_id(legacy_profile_id)
connection = store.ensure(
connection_id,
legacy_profile.id,
str(raw.get("label") or legacy_profile.label),
)
else:
connection = store.get(connection_id)
profile = profile_by_id(connection.profile_id)
if profile not in eligible_profiles():
raise ValueError(
f"connection is not eligible for read-only portfolios: {connection_id}"
)
if connection_id in seen_ids:
raise ValueError("portfolio connection ids must be unique")
label = str(raw.get("label") or connection.label).strip()
if (
not label
or len(label) > 80
or any(ord(character) < 32 for character in label)
):
raise ValueError(
"portfolio source labels must contain 1 to 80 printable characters"
)
seen_ids.add(connection_id)
sources.append(
PortfolioSource(
connection_id=connection_id,
label=label,
enabled=bool(raw.get("enabled", True)),
order=int(raw.get("order", index)),
include_cash=bool(raw.get("include_cash", True)),
)View on GitHub (pinned to 80ffdda44c)
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
Example fix
python - <<'PY'
import json
p = json.load(open('portfolio.json'))
seen = 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'))]
json.dump(p, open('portfolio.json','w'), indent=2)
PY Defensive patterns
Strategy: validation
Validate before calling
seen = set(); unique = []
for s in payload['sources']:
cid = (s.get('connection_id') or s.get('id'))
if cid not in seen:
seen.add(cid); unique.append(s)
payload['sources'] = unique Type guard
def sources_are_unique(payload) -> bool:
ids = [(s.get('connection_id') or s.get('id')) for s in payload['sources']]
return len(ids) == len(set(ids)) Try / catch
try:
settings = parse_settings(payload, store)
except ValueError as exc:
if 'must be unique' in str(exc):
payload['sources'] = dedupe_by_id(payload['sources'])
settings = parse_settings(payload, store) Prevention
- 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
When it happens
Trigger: 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.
Common situations: Concatenating configs, adding a source that already exists with a different label, or copy-paste duplication inside the JSON array.
Related errors
- max_bytes must be positive, got {max_bytes}
- display_currency must be USD or CNY
- sources must be a list
- at most 50 portfolio sources are allowed
- each portfolio source must be an object
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/f6522988224c9808.
Report an issue: GitHub.