MadsLorentzen/ai-job-search · error · ValueError

ambiguous comma separator

Error message

ambiguous comma separator

What it means

Raised when a string contains exactly one comma in the pattern digits,3-digits (e.g. '1,234'). This matches both US thousands ('1,234' = 1234) and European decimal ('1,234' = 1.234), so converting it either way risks a 1000x error; the function refuses rather than guess.

Source

Thrown at tools/convert_salary_excel.py:77

    if isinstance(value, (int, float)):
        return float(value)
    if not isinstance(value, str):
        raise ValueError("not numeric")

    text = value.strip().replace("\u00a0", " ").replace(" ", "")
    if not text:
        raise ValueError("not numeric")
    if "," in text and "." in text:
        # The separator that appears last is the decimal separator: European
        # "1.234,56" and US "1,234.56" are both unambiguous here, unlike the
        # single-separator cases below.
        if text.rfind(",") > text.rfind("."):
            text = text.replace(".", "").replace(",", ".")
        else:
            text = text.replace(",", "")
    elif "," in text:
        if re.fullmatch(r"[+-]?\d+,\d{3}", text):
            raise ValueError("ambiguous comma separator")
        text = text.replace(",", ".")
    elif "." in text:
        if re.fullmatch(r"[+-]?\d+\.\d{3}", text):
            raise ValueError("ambiguous dot separator")
    return float(text)


def header_matches(header, patterns):
    """Return True when a header contains a meaningful pattern match.

    Patterns match whole tokens; any pattern also listed in
    ``COMPOUND_PATTERNS`` may additionally match as a substring, to handle
    languages that form compound words.
    """
    h = header.lower().strip()
    tokens = set(re.findall(r"[a-zæøåöäü0-9]+", h))

    for p in patterns:

View on GitHub (pinned to 79cd383e58)

Solutions

  1. Disambiguate the locale before parsing: if you know the sheet is European, rewrite the comma to a dot first ('1,234' -> '1.234'); if US, strip the comma
  2. Add more context, e.g. pass values with an explicit decimal part ('1,234.0' or '1,234,00' are unambiguous)
  3. Catch this ValueError in parse_sheet, log the raw cell, and resolve manually or via a locale parameter

Example fix

// before
num = parse_numeric_cell('1,234')  # raises

// after
num = parse_numeric_cell('1,234'.replace(',', '') if locale == 'us' else '1,234'.replace(',', '.'))
Defensive patterns

Strategy: try-catch

Validate before calling

import re
AMBIG = re.compile(r'[+-]?\d+,\d{3}$')
if isinstance(v, str) and AMBIG.fullmatch(v.strip()):
    v = v.replace(',', '.' if locale == 'eu' else '')

Type guard

def is_ambiguous_comma(v) -> bool:
    return isinstance(v, str) and bool(re.fullmatch(r'[+-]?\d+,\d{3}', v.strip()))

Try / catch

try:
    num = parse_numeric_cell(v)
except ValueError as e:
    if 'ambiguous comma' in str(e):
        raise LocaleNeeded(v)  # surface for manual/locale resolution
    raise

Prevention

When it happens

Trigger: Passing a string like '1,234', '42,000', or '-9,999' that fullmatches r'[+-]?\d+,\d{3}'. Common when a sheet has US-formatted thousands without a decimal part, or a European decimal with exactly three fraction digits.

Common situations: Excel cells formatted with thousands separators exported as text ('1,234'), or a locale mismatch: a Danish/European sheet where '1,234' means 1.234 parsed with US assumptions. Any single-group thousands value with exactly 3 digits after the comma triggers it by design.

Related errors


AI-assisted analysis of MadsLorentzen/ai-job-search@79cd383e58 (2026-08-27). Data as JSON: /api/errors/460264f381fc83d3. Report an issue: GitHub.