HKUDS/Vibe-Trading · error · ValueError

portfolio source labels must contain 1 to 80 printable chara

Error message

portfolio source labels must contain 1 to 80 printable characters

What it means

Each source's label (explicit or inherited from the connection) must be 1-80 characters with no control characters (< 0x20). Empty, over-length, or control-character labels are rejected during parsing.

Source

Thrown at agent/src/portfolio/config.py:189

                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)),
            )
        )
    return PortfolioSettings(
        display_currency=currency,
        sources=tuple(sorted(sources, key=lambda item: (item.order, item.id))),
    )

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Set a concise label (1-80 printable characters)
  2. Truncate generated labels: label[:80]
  3. Strip control characters from pasted text before saving

Example fix

# before
{"connection_id": "binance-main", "label": ""}
# after
{"connection_id": "binance-main", "label": "Binance main account"}
Defensive patterns

Strategy: validation

Validate before calling

label = ''.join(ch for ch in (label or '').strip() if ord(ch) >= 32)[:80]
if not label:
    label = cid  # fallback to the connection id itself
entry['label'] = label

Type guard

def is_valid_label(label) -> bool:
    return bool(label) and len(label) <= 80 and all(ord(c) >= 32 for c in label)

Try / catch

try:
    settings = parse_settings(payload, store)
except ValueError as exc:
    if 'labels must contain' in str(exc):
        for e in payload['sources']:
            e['label'] = sanitize_label(e.get('label')) or (e.get('connection_id') or 'source')
        settings = parse_settings(payload, store)

Prevention

When it happens

Trigger: label = '', ' ' (after strip), an 81+ character label, labels containing '\n'/'\t'/null bytes, or a connection whose stored label is blank so the fallback fails too.

Common situations: Omitting labels assuming defaults exist, pasting multi-line text into a label field, unicode paste introducing control chars, or scripted configs generating labels from unbounded strings.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/3ee5af3876d3d787. Report an issue: GitHub.