{"record":{"id":"82a139d2d19676b2","repo":"HKUDS/Vibe-Trading","slug":"sector-sector-r-has-no-portfolio-return-and-no-b","errorCode":null,"errorMessage":"sector {sector!r} has no portfolio return and no benchmark return","messagePattern":"sector (.+?) has no portfolio return and no benchmark return","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/attribution.py","lineNumber":276,"sourceCode":"    benchmark_total = math.fsum(benchmark_weights.values())\n    if abs(portfolio_total - benchmark_total) > weight_sum_tolerance:\n        raise ValueError(\n            \"portfolio and benchmark weights must sum to the same total for the Brinson \"\n            f\"identity to hold; got {portfolio_total!r} and {benchmark_total!r} \"\n            f\"(difference {portfolio_total - benchmark_total!r} exceeds {weight_sum_tolerance!r})\"\n        )\n\n    resolved: list[tuple[str, float, float, float, float]] = []\n    for sector in ordered:\n        w_p = float(portfolio_weights.get(sector, 0.0))\n        w_b = float(benchmark_weights.get(sector, 0.0))\n        r_p = portfolio_returns.get(sector)\n        r_b = benchmark_returns.get(sector)\n        if r_p is None:\n            if w_p != 0.0:\n                raise ValueError(f\"sector {sector!r} has portfolio weight {w_p!r} but no portfolio return\")\n            if r_b is None:\n                raise ValueError(f\"sector {sector!r} has no portfolio return and no benchmark return\")\n            r_p = r_b\n        if r_b is None:\n            if w_b != 0.0:\n                raise ValueError(f\"sector {sector!r} has benchmark weight {w_b!r} but no benchmark return\")\n            r_b = r_p\n        resolved.append((sector, w_p, w_b, float(r_p), float(r_b)))\n\n    total_portfolio_return = math.fsum(w_p * r_p for _, w_p, _, r_p, _ in resolved)\n    total_benchmark_return = math.fsum(w_b * r_b for _, _, w_b, _, r_b in resolved)\n\n    effects: list[SectorEffect] = []\n    for sector, w_p, w_b, r_p, r_b in resolved:\n        active_weight = w_p - w_b\n        effects.append(\n            SectorEffect(\n                sector=sector,\n                portfolio_weight=w_p,\n                benchmark_weight=w_b,","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/attribution.py#L258-L294","documentation":"A sector exists in the weight universe with zero portfolio weight and no return on either side. Since w_p == 0 the portfolio-return branch falls through, but r_b is also None, leaving no defensible return value, so the function raises rather than inventing 0.0.","triggerScenarios":"A sector appears in benchmark_weights (weight 0 on the portfolio side) but is absent from both portfolio_returns and benchmark_returns — typically an unpriced instrument in the benchmark universe.","commonSituations":"Benchmark membership lists including sectors with no return coverage for the period; stale reference data; weekends/holidays where one feed has no rows.","solutions":["Drop sectors with zero weight on both sides and no returns from the inputs before calling","Extend the returns feed to cover the full benchmark universe","Explicitly map the sector's return to a value (0.0) upstream if that is the accepted convention"],"exampleFix":"# before\npw, bw = {}, {\"ghost\": 0.0}\nbrinson_fachler(pw, bw, {}, {})\n\n# after\nbw = {s: w for s, w in bw.items() if s in benchmark_returns or s in portfolio_returns}\nbrinson_fachler(pw, bw, portfolio_returns, benchmark_returns)","handlingStrategy":"validation","validationCode":"universe = set(portfolio_weights) | set(benchmark_weights)\nuniverse = {s for s in universe if s in portfolio_returns or s in benchmark_returns}\n# pass weights/returns restricted to `universe`","typeGuard":"def fully_priced(pw, bw, rp, rb) -> bool:\n    return all((s in rp or s in rb) for s in set(pw) | set(bw))","tryCatchPattern":null,"preventionTips":["Filter the sector universe to priced instruments before attribution","Monitor returns feeds for coverage gaps on benchmark constituents"],"tags":["quantlib","attribution","missing-data"],"backgroundTag":"missing-return-data","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}