HKUDS/Vibe-Trading · error · ValueError

conflicting rates for {key}: {indexed[key].rate!r} vs {entry

Error message

conflicting rates for {key}: {indexed[key].rate!r} vs {entry.rate!r}

What it means

from_rates indexes rates by (base_currency, date); if the same key appears twice with different rate values, the contradiction is rejected instead of silently keeping whichever came last, which would pick an arbitrary FX number.

Source

Thrown at agent/src/entities/cashflow.py:576

        Args:
            rates: The quotes, all against ``quote_currency``.
            quote_currency: The reporting currency of the table.

        Returns:
            A new ``FxRateTable`` keyed by ``(base_currency, date)``.

        Raises:
            ValueError: If a member is not an ``FxRate``, two quotes collide
                on the same ``(base_currency, date)`` with different rates,
                or a quote's ``quote_currency`` disagrees with the table's.
        """
        indexed: dict[tuple[str, date], FxRate] = {}
        for entry in rates:
            if not isinstance(entry, FxRate):
                raise ValueError(f"rates must contain FxRate, got {type(entry).__name__}")
            key = (entry.base_currency, entry.date)
            if key in indexed and indexed[key].rate != entry.rate:
                raise ValueError(
                    f"conflicting rates for {key}: {indexed[key].rate!r} vs "
                    f"{entry.rate!r}"
                )
            indexed[key] = entry
        return cls(quote_currency=quote_currency, rates=indexed)

    @classmethod
    def from_mapping(
        cls,
        mapping: Mapping[tuple[str, "date | datetime | str"], float],
        *,
        quote_currency: str,
    ) -> "FxRateTable":
        """Build a table from ``{(base_currency, date): rate}`` pairs.

        Args:
            mapping: Each value is units of ``quote_currency`` per 1 unit of
                the key's currency, exactly as ``FxRate.rate`` defines it.

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Deduplicate by (base_currency, date), keeping the authoritative value (e.g. latest revision) before calling from_rates
  2. If values disagree, investigate which source is right rather than dropping one arbitrarily
  3. Keep only the max-date record per key when merging revision feeds

Example fix

# before
FxRateTable.from_rates(rates, quote_currency='USD')  # rates has conflicting duplicates
# after
best = {}
for r in rates:
    k = (r.base_currency, r.date)
    if k not in best or r.date >= best[k].date:
        best[k] = r
table = FxRateTable.from_rates(list(best.values()), quote_currency='USD')
Defensive patterns

Strategy: validation

Validate before calling

dedup = {}
for r in rates:
    k = (r.base_currency, r.date)
    if k not in dedup or r.rate == dedup[k].rate:
        dedup[k] = r
rates = list(dedup.values())

Try / catch

try:
    table = FxRateTable.from_rates(rates, quote_currency=q)
except ValueError as e:
    if 'conflicting rates' in str(e):
        keep latest revision per key and retry

Prevention

When it happens

Trigger: from_rates([FxRate('EUR','USD',d,1.0850), FxRate('EUR','USD',d,1.0900)], quote_currency='USD').

Common situations: Concatenating daily and intraday feeds covering the same day with revised values; duplicate rows in a CSV with one mistyped rate; re-fetching data appended to a stale list. Identical duplicates (same rate) are fine.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/ab888d339a8826c9. Report an issue: GitHub.