{"record":{"id":"5e9d15b9d7698117","repo":"HKUDS/Vibe-Trading","slug":"rates-must-contain-fxrate-got-type-entry-name","errorCode":null,"errorMessage":"rates must contain FxRate, got {type(entry).__name__}","messagePattern":"rates must contain FxRate, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/entities/cashflow.py","lineNumber":573,"sourceCode":"    def from_rates(cls, rates: Iterable[FxRate], *, quote_currency: str) -> \"FxRateTable\":\n        \"\"\"Build a table from a sequence of individual quotes.\n\n        Args:\n            rates: The quotes, all against ``quote_currency``.\n            quote_currency: The reporting currency of the table.\n\n        Returns:\n            A new ``FxRateTable`` keyed by ``(base_currency, date)``.\n\n        Raises:\n            ValueError: If a member is not an ``FxRate``, two quotes collide\n                on the same ``(base_currency, date)`` with different rates,\n                or a quote's ``quote_currency`` disagrees with the table's.\n        \"\"\"\n        indexed: dict[tuple[str, date], FxRate] = {}\n        for entry in rates:\n            if not isinstance(entry, FxRate):\n                raise ValueError(f\"rates must contain FxRate, got {type(entry).__name__}\")\n            key = (entry.base_currency, entry.date)\n            if key in indexed and indexed[key].rate != entry.rate:\n                raise ValueError(\n                    f\"conflicting rates for {key}: {indexed[key].rate!r} vs \"\n                    f\"{entry.rate!r}\"\n                )\n            indexed[key] = entry\n        return cls(quote_currency=quote_currency, rates=indexed)\n\n    @classmethod\n    def from_mapping(\n        cls,\n        mapping: Mapping[tuple[str, \"date | datetime | str\"], float],\n        *,\n        quote_currency: str,\n    ) -> \"FxRateTable\":\n        \"\"\"Build a table from ``{(base_currency, date): rate}`` pairs.\n","sourceCodeStart":555,"sourceCodeEnd":591,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/entities/cashflow.py#L555-L591","documentation":"FxRateTable.from_rates iterates the input and requires every element to be an FxRate; anything else (dicts, floats, tuples from a parsed feed) fails with the type name before indexing by (base_currency, date).","triggerScenarios":"FxRateTable.from_rates([{'base':'EUR','rate':1.08}, ...], quote_currency='USD') or a list of (base, date, rate) tuples.","commonSituations":"Feeding raw rows from a rates API or CSV straight into from_rates; passing pandas itertuples() results; test fixtures with placeholder tuples.","solutions":["Convert each row to FxRate(base_currency, quote_currency, date, rate) before calling from_rates","If rows come from a mapping format, use from_mapping, which performs the conversion"],"exampleFix":"# before\nFxRateTable.from_rates(rows, quote_currency='USD')  # rows are dicts\n# after\nrates = [FxRate(r['base'], 'USD', parse_date(r['date']), float(r['rate'])) for r in rows]\ntable = FxRateTable.from_rates(rates, quote_currency='USD')","handlingStrategy":"type-guard","validationCode":"from agent.src.entities.cashflow import FxRate\nassert all(isinstance(r, FxRate) for r in rates)","typeGuard":"from agent.src.entities.cashflow import FxRate\ndef all_fx_rates(seq) -> bool:\n    return all(isinstance(r, FxRate) for r in seq)","tryCatchPattern":"try:\n    table = FxRateTable.from_rates(rates, quote_currency=q)\nexcept ValueError as e:\n    if 'must contain FxRate' in str(e):\n        rates = [FxRate(r['base'], q, parse(r['date']), float(r['rate'])) for r in rates]","preventionTips":["Map feed rows to FxRate immediately after parsing","Use from_mapping for dict-shaped payloads"],"tags":["python","fx-rate","type-validation"],"backgroundTag":"container-type-validation","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}