{"record":{"id":"50e4df3ecfe22c32","repo":"HKUDS/Vibe-Trading","slug":"fxrate-stored-under-key-key-r-does-not-match-its","errorCode":null,"errorMessage":"FxRate stored under key {key!r} does not match its own (base_currency, date) = {expected_key!r}","messagePattern":"FxRate stored under key (.+?) does not match its own \\(base_currency, date\\) = (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/entities/cashflow.py","lineNumber":547,"sourceCode":"                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\n    @classmethod\n    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:","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/entities/cashflow.py#L529-L565","documentation":"FxRateTable's rates mapping must be keyed by each entry's own (base_currency, date). A key that doesn't match the entry's fields would make lookups return the wrong rate, so construction fails with both the stored key and the expected key.","triggerScenarios":"FxRateTable(quote_currency='USD', rates={('EUR', wrong_date): FxRate('EUR','USD',right_date,1.0850)}).","commonSituations":"Hand-building the dict and letting keys drift from entry dates (e.g. normalizing dates only on the value side); copying entries between tables while re-keying for a different period.","solutions":["Key by (entry.base_currency, entry.date) exactly","Or avoid manual keying entirely: pass a flat iterable to FxRateTable.from_rates, which computes the keys"],"exampleFix":"# before\nFxRateTable(quote_currency='USD', rates={('EUR', d2): FxRate('EUR','USD',d1,1.0850)})\n# after\ntable = FxRateTable.from_rates([FxRate('EUR','USD',d1,1.0850)], quote_currency='USD')","handlingStrategy":"validation","validationCode":"indexed = {(e.base_currency, e.date): e for e in rate_entries}\ntable = FxRateTable(quote_currency=q, rates=indexed)","typeGuard":null,"tryCatchPattern":"try:\n    FxRateTable(...)\nexcept ValueError as e:\n    if 'does not match its own' in str(e):\n        re-key by (entry.base_currency, entry.date) and retry","preventionTips":["Derive keys from entries, never maintain them by hand","Use from_rates so keys are computed for you"],"tags":["python","fx-rate","dict-key-validation"],"backgroundTag":"dict-key-mismatch","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}