HKUDS/Vibe-Trading · error · ValueError

{text!r} uses a single comma and could be either {text.repla

Error message

{text!r} uses a single comma and could be either {text.replace(',', '')} (comma groups thousands) or {text.replace(',', '.')} (comma is the decimal separator); pass decimal_separator='.' or decimal_separator=',' to say which

What it means

Raised (as ValueError from _to_plain_number) when a numeric cell contains exactly one comma and no dot, making the number ambiguous: '1,234' could be 1234 (thousands grouping) or 1.234 (decimal comma). The library refuses to guess because either interpretation yields a plausible but different number; the caller must disambiguate via decimal_separator.

Source

Thrown at agent/src/entities/ingest.py:168

        ValueError: If the value uses a single comma whose role cannot be
            determined -- ``"1,234"`` is 1234 in a US export and 1.234 in a
            European one, and the data cannot say which.
    """
    if decimal_separator is not None:
        grouping = "," if decimal_separator == "." else "."
        return text.replace(grouping, "").replace(decimal_separator, ".")

    has_dot = "." in text
    has_comma = "," in text
    if has_dot and has_comma:
        # The rightmost separator is the decimal one; the other groups digits.
        if text.rindex(".") > text.rindex(","):
            return text.replace(",", "")
        return text.replace(".", "").replace(",", ".")
    if has_comma:
        if text.count(",") > 1:
            return text.replace(",", "")  # 1,234,567 cannot be a decimal comma
        raise ValueError(
            f"{text!r} uses a single comma and could be either "
            f"{text.replace(',', '')} (comma groups thousands) or "
            f"{text.replace(',', '.')} (comma is the decimal separator); pass "
            "decimal_separator='.' or decimal_separator=',' to say which"
        )
    return text


def _parse_amount(
    raw: str,
    path: Path,
    row_number: int,
    decimal_separator: str | None = None,
) -> float:
    """Parse a numeric amount from a file field.

    Handles currency symbols, digit grouping, and the accounting convention
    where parentheses or a trailing minus denote a negative number, e.g.

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Inspect the raw value cited in the message and determine whether the comma groups thousands or marks decimals
  2. Pass decimal_separator='.' if commas group thousands, or decimal_separator=',' if the comma is the decimal separator
  3. For per-file locales, load each file with its own decimal_separator rather than a global setting
  4. If the file mixes conventions, normalize the source data first

Example fix

# before
flows = load_cashflows('eu_export.csv')
# after
flows = load_cashflows('eu_export.csv', decimal_separator=',')
Defensive patterns

Strategy: validation

Validate before calling

import re

def detect_ambiguous(cell: str) -> bool:
    return cell.count(',') == 1 and '.' not in cell

ambiguous = [r for r in rows if detect_ambiguous(r['amount'])]
if ambiguous:
    raise SystemExit('ambiguous decimals; choose decimal_separator explicitly')

Type guard

def is_unambiguous_number(text: str) -> bool:
    t = text.strip()
    return not (t.count(',') == 1 and '.' not in t)

Try / catch

try:
    load_cashflows(p)
except CashFlowIngestError as e:
    if 'could be either' in str(e):
        load_cashflows(p, decimal_separator=decide_by_locale_of(p))

Prevention

When it happens

Trigger: load_cashflows / _parse_amount encounters a cell like '1,234' or '12,5' and decimal_separator is None. Values with multiple commas ('1,234,567') or with both separators are resolved automatically; only the single-comma/no-dot case raises.

Common situations: European exports with decimal commas ('1234,5' with one digit after) that look like thousands groups; US exports with a single thousands comma ('1,234'); mixed-locale CSVs loaded without configuration.

Related errors


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