{"record":{"id":"845368424d6c9344","repo":"HKUDS/Vibe-Trading","slug":"fxratetable-entries-must-be-fxrate-got-type-entr","errorCode":null,"errorMessage":"FxRateTable entries must be FxRate, got {type(entry).__name__}","messagePattern":"FxRateTable entries must be FxRate, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/entities/cashflow.py","lineNumber":535,"sourceCode":"    \"\"\"\n\n    quote_currency: str\n    rates: Mapping[tuple[str, date], FxRate] = field(default_factory=dict)\n\n    def __post_init__(self) -> None:\n        \"\"\"Validate the quote currency and every entry's consistency.\n\n        Raises:\n            ValueError: If ``quote_currency`` is invalid, a value is not an\n                ``FxRate``, an entry quotes against a different currency than\n                the table's, or an entry is stored under a key that does not\n                match its own ``(base_currency, date)``.\n        \"\"\"\n        quote = normalize_currency(self.quote_currency, field_name=\"quote_currency\")\n        rates = dict(self.rates)\n        for key, entry in rates.items():\n            if not isinstance(entry, FxRate):\n                raise ValueError(\n                    f\"FxRateTable entries must be FxRate, got {type(entry).__name__}\"\n                )\n            if entry.quote_currency != quote:\n                raise ValueError(\n                    f\"FxRate {entry.base_currency}/{entry.quote_currency}@\"\n                    f\"{entry.date} does not quote against this table's \"\n                    f\"currency {quote!r}; a table may only hold rates quoted \"\n                    \"against one reporting currency\"\n                )\n            expected_key = (entry.base_currency, entry.date)\n            if key != expected_key:\n                raise ValueError(\n                    f\"FxRate stored under key {key!r} does not match its own \"\n                    f\"(base_currency, date) = {expected_key!r}\"\n                )\n        object.__setattr__(self, \"quote_currency\", quote)\n        object.__setattr__(self, \"rates\", MappingProxyType(rates))\n","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/entities/cashflow.py#L517-L553","documentation":"FxRateTable validates that every value in its rates mapping is an FxRate instance. Mixing in dicts, floats, or tuples fails immediately with the offending type name, because the table relies on FxRate's own invariants (normalized currency/date, positive rate).","triggerScenarios":"FxRateTable(quote_currency='USD', rates={('EUR', d): {'rate': 1.08}}) or rates={('EUR', d): 1.08}.","commonSituations":"Building a table from raw parsed rows without an FxRate step; deserializing a mapping whose values lost their type; storing plain numbers for convenience in prototypes.","solutions":["Construct FxRate objects first and use those as values: rates={('EUR', d): FxRate('EUR','USD',d,1.0850)}","Or use the FxRateTable.from_rates(iterable_of_FxRate) factory, which builds the keyed mapping for you"],"exampleFix":"# before\nFxRateTable(quote_currency='USD', rates={('EUR', d): 1.0850})\n# after\nFxRateTable(quote_currency='USD', rates={('EUR', d): FxRate('EUR','USD',d,1.0850)})","handlingStrategy":"type-guard","validationCode":"assert all(isinstance(v, FxRate) for v in rates.values())","typeGuard":"from agent.src.entities.cashflow import FxRate\ndef all_fx_rates(mapping) -> bool:\n    return all(isinstance(v, FxRate) for v in mapping.values())","tryCatchPattern":"try:\n    FxRateTable(quote_currency=q, rates=mapping)\nexcept ValueError as e:\n    if 'must be FxRate' in str(e):\n        mapping = {k: FxRate(k[0], q, k[1], v['rate']) for k, v in mapping.items()}","preventionTips":["Prefer FxRateTable.from_rates to avoid manual dict building","Construct entities at the parse boundary, not at table build time"],"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"}