HKUDS/Vibe-Trading · error · ValueError

weights must be an object mapping symbol → number

Error message

weights must be an object mapping symbol → number

What it means

_parse_weights accepts either None (equal weights) or a Mapping from symbol to number. Passing a list, string, or scalar raises 'weights must be an object mapping symbol → number'.

Source

Thrown at agent/src/tools/portfolio_risk_tool.py:139

            "status": "ok",
            "data": report,
            "meta": {
                "start_date": start_date,
                "end_date": end_date,
                "interval": interval,
                "source": source,
                "unresolved_symbols": list(unresolved or []),
            },
        }
        return json.dumps(envelope, ensure_ascii=False, indent=2, allow_nan=False)

    # ------------------------------------------------------------------
    @staticmethod
    def _parse_weights(raw: Any, symbols: list[str]) -> dict[str, float]:
        if raw is None:
            return {sym: 1.0 / len(symbols) for sym in symbols}
        if not isinstance(raw, Mapping):
            raise ValueError("weights must be an object mapping symbol → number")
        unknown = [sym for sym in raw if sym not in symbols]
        if unknown:
            raise ValueError(f"weights name symbols not in the basket: {sorted(unknown)}")
        missing = [sym for sym in symbols if sym not in raw]
        if missing:
            raise ValueError(f"weights missing basket symbols: {sorted(missing)}")
        return {sym: raw[sym] for sym in symbols}

    @staticmethod
    def _parse_dates(start_raw: Any, end_raw: Any) -> tuple[str, str]:
        end = (
            datetime.strptime(end_raw, "%Y-%m-%d").date()
            if isinstance(end_raw, str) and end_raw
            else datetime.now(timezone.utc).date()
        )
        start = (
            datetime.strptime(start_raw, "%Y-%m-%d").date()
            if isinstance(start_raw, str) and start_raw

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Send an object keyed by ticker: {"AAPL": 0.6, "MSFT": 0.4}
  2. Omit weights entirely for equal weighting
  3. Convert list weights: dict(zip(symbols, weights))

Example fix

# before
execute(symbols=["AAPL","MSFT"], weights=[0.6, 0.4])
# after
execute(symbols=["AAPL","MSFT"], weights={"AAPL": 0.6, "MSFT": 0.4})
Defensive patterns

Strategy: type-guard

Validate before calling

if weights is not None and not isinstance(weights, dict):
    weights = dict(zip(symbols, weights)) if isinstance(weights, list) else None
# None -> equal weights

Type guard

from collections.abc import Mapping
def is_weight_map(w: object) -> bool:
    return w is None or (isinstance(w, Mapping) and all(isinstance(k, str) for k in w))

Try / catch

try:
    out = tool.execute(symbols=symbols, weights=weights)
except ValueError as e:
    if "object mapping" in str(e):
        out = tool.execute(symbols=symbols, weights=dict(zip(symbols, weights)))

Prevention

When it happens

Trigger: weights=[0.5, 0.5], weights='equal', weights=0.5, or a JSON array of {sym,w} objects.

Common situations: LLMs emitting arrays because JSON arrays are more common than objects, or callers reusing vector weights from numpy code.

Related errors


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