{"record":{"id":"7c62fdb1a95ebabd","repo":"HKUDS/Vibe-Trading","slug":"weights-missing-basket-symbols-sorted-missing","errorCode":null,"errorMessage":"weights missing basket symbols: {sorted(missing)}","messagePattern":"weights missing basket symbols: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/tools/portfolio_risk_tool.py","lineNumber":145,"sourceCode":"                \"source\": source,\n                \"unresolved_symbols\": list(unresolved or []),\n            },\n        }\n        return json.dumps(envelope, ensure_ascii=False, indent=2, allow_nan=False)\n\n    # ------------------------------------------------------------------\n    @staticmethod\n    def _parse_weights(raw: Any, symbols: list[str]) -> dict[str, float]:\n        if raw is None:\n            return {sym: 1.0 / len(symbols) for sym in symbols}\n        if not isinstance(raw, Mapping):\n            raise ValueError(\"weights must be an object mapping symbol → number\")\n        unknown = [sym for sym in raw if sym not in symbols]\n        if unknown:\n            raise ValueError(f\"weights name symbols not in the basket: {sorted(unknown)}\")\n        missing = [sym for sym in symbols if sym not in raw]\n        if missing:\n            raise ValueError(f\"weights missing basket symbols: {sorted(missing)}\")\n        return {sym: raw[sym] for sym in symbols}\n\n    @staticmethod\n    def _parse_dates(start_raw: Any, end_raw: Any) -> tuple[str, str]:\n        end = (\n            datetime.strptime(end_raw, \"%Y-%m-%d\").date()\n            if isinstance(end_raw, str) and end_raw\n            else datetime.now(timezone.utc).date()\n        )\n        start = (\n            datetime.strptime(start_raw, \"%Y-%m-%d\").date()\n            if isinstance(start_raw, str) and start_raw\n            else end - timedelta(days=_DEFAULT_LOOKBACK_DAYS)\n        )\n        if start >= end:\n            raise ValueError(f\"start_date {start} must be before end_date {end}\")\n        return start.isoformat(), end.isoformat()\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/tools/portfolio_risk_tool.py#L127-L163","documentation":"Raised by PortfolioRiskTool._parse_weights when the user-supplied weights mapping does not include an entry for every symbol in the basket. The tool requires weights to be complete: keys must exactly equal the basket symbol set (no unknowns, no omissions). Missing keys make portfolio weights impossible to normalize, so it fails fast with the sorted list of omitted symbols.","triggerScenarios":"Calling the portfolio risk tool with a weights object whose keys are a strict subset of the basket symbols, e.g. basket ['AAPL','MSFT','NVDA'] with weights {'AAPL':0.5}. Also happens when a symbol name has a typo or different casing so it is treated as 'unknown' first, or after whitespace differences like 'AAPL ' vs 'AAPL'.","commonSituations":"LLM-generated tool calls that fabricate partial weight maps; users copy-pasting weights from a spreadsheet that drops zero-weight rows; baskets changed server-side while the caller cached an old symbol list.","solutions":["Add the listed missing symbols to the weights object so its keys exactly match the basket symbols","Check for whitespace/case mismatches in symbol keys (e.g. 'aapl' vs 'AAPL') that cause symbols to be seen as missing","Assign 0.0 to symbols you want to exclude rather than omitting them","If symbols are unknown too, fix those first — the unknown-symbol check runs before this one"],"exampleFix":"# before\nweights = {\"AAPL\": 0.5, \"MSFT\": 0.5}  # basket is AAPL, MSFT, NVDA\n\n# after\nweights = {\"AAPL\": 0.5, \"MSFT\": 0.3, \"NVDA\": 0.2}","handlingStrategy":"validation","validationCode":"basket = set(symbols)\nweights_keys = set(weights)\nmissing = basket - weights_keys\nunknown = weights_keys - basket\nif missing or unknown:\n    raise ValueError(f\"weights mismatch: missing={sorted(missing)}, unknown={sorted(unknown)}\")\nweights = {s: float(weights.get(s, 0.0)) for s in symbols}","typeGuard":"def valid_weights(weights: object, symbols: list[str]) -> bool:\n    return (\n        isinstance(weights, dict)\n        and set(weights) == set(symbols)\n        and all(isinstance(v, (int, float)) for v in weights.values())\n    )","tryCatchPattern":"try:\n    result = portfolio_risk_tool.run(...)\nexcept ValueError as e:\n    if \"weights\" in str(e):\n        weights = {s: float(raw_weights.get(s, 0.0)) for s in symbols}  # backfill and retry","preventionTips":["Always derive weight keys from the same symbol list passed to the tool","Include explicit 0.0 entries instead of omitting symbols","Strip/normalize symbol keys (whitespace, case) before building the weights map"],"tags":["portfolio-risk","weights","validation","input-validation"],"backgroundTag":"input-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}