iOfficeAI/OfficeCLI · error · ArgumentException

Cannot store '{cell.CellValue?.Text}' as number; value must

Error message

Cannot store '{cell.CellValue?.Text}' as number; value must be a finite numeric literal. Use type=string to keep the literal text.

What it means

A type=number cell stores its value in <v> with no t= attribute, so a non-numeric value produces spec-invalid numeric content (<v>notanumber</v>) that makes real Excel refuse the whole file (0x800A03EC) while schema validation stays green. This guard parses the cell text with double.TryParse (InvariantCulture, Any NumberStyles) and rejects non-finite or unparseable values up front, mirroring the boolean/date guards.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs:723

                        // mirroring the type=date guard.
                        throw new ArgumentException(
                            $"Cannot store '{cell.CellValue?.Text}' as boolean; value must be true/false, yes/no, or 1/0. " +
                            "Use type=string to keep the literal text.");
                }
                // A type=number cell stores its value in <v> with no t=
                // attribute, so a non-numeric value produces spec-invalid
                // numeric content (<v>notanumber</v>) that makes real Excel
                // refuse the whole file (0x800A03EC) while schema validation
                // stays green. Reject up front, mirroring the boolean/date
                // guards above.
                if (cellType.ToLowerInvariant() is "number" or "num")
                {
                    var numText = cell.CellValue?.Text?.Trim();
                    if (!string.IsNullOrEmpty(numText)
                        && (!double.TryParse(numText, System.Globalization.NumberStyles.Any,
                                System.Globalization.CultureInfo.InvariantCulture, out var numDbl)
                            || !double.IsFinite(numDbl)))
                        throw new ArgumentException(
                            $"Cannot store '{cell.CellValue?.Text}' as number; value must be a finite numeric literal. " +
                            "Use type=string to keep the literal text.");
                }
                // CONSISTENCY(cell-type-parity): mirror Set's value auto-detect
                // path (ExcelHandler.Set.cs lines 1025-1033) — parse the cell
                // value as an ISO date and write it back as an OADate double so
                // Excel renders it as a real date instead of a literal string.
                if (cellType.Equals("date", StringComparison.OrdinalIgnoreCase))
                {
                    var dateText = cell.CellValue?.Text?.Trim();
                    // R13-2: accept ISO date-with-time (T separator) as well.
                    if (!string.IsNullOrEmpty(dateText)
                        && TryParseIsoDateFlexible(dateText, out var dt))
                    {
                        // Mirrors Set's pre-1900 guard: Excel's serial epoch is
                        // 1899-12-30; earlier dates round-trip as the epoch and
                        // mislead the user. Reject instead of silently clamping.
                        if (dt < new System.DateTime(1900, 1, 1))

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Pass a finite numeric literal using a period as the decimal separator (InvariantCulture format), e.g. "3.14".
  2. If the value may be text, use type=string instead of type=number.
  3. Sanitize locale-specific formatting (strip thousands separators, convert comma decimals) before the call.

Example fix

// before
handler.Add("/Sheet1/A1", "cell", null, new() { ["type"] = "number", ["value"] = "1.234,56" });
// after
var num = double.Parse("1.234,56", CultureInfo.GetCultureInfo("de-DE"));
handler.Add("/Sheet1/A1", "cell", null, new() { ["type"] = "number", ["value"] = num.ToString(CultureInfo.InvariantCulture) });
Defensive patterns

Strategy: validation

Validate before calling

if (props.GetValueOrDefault("type")?.ToLowerInvariant() is "number" or "num")
{
    var n = props.GetValueOrDefault("value");
    if (!string.IsNullOrEmpty(n) && (!double.TryParse(n, NumberStyles.Any, CultureInfo.InvariantCulture, out var d) || !double.IsFinite(d)))
        throw new ArgumentException("value is not a finite numeric literal");
    props["value"] = double.Parse(n!, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture);
}
h.Add(parentPath, "cell", pos, props);

Type guard

static bool IsFiniteNumeric(string? s) =>
    !string.IsNullOrEmpty(s) && double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out var d) && double.IsFinite(d);

Try / catch

try { h.Add(parentPath, "cell", pos, props); }
catch (ArgumentException ex) when (ex.Message.Contains("as number"))
{ /* fall back to type=string or sanitize locale formatting */ }

Prevention

When it happens

Trigger: Add("/Sheet1/A1","cell",pos,{["type"]="number",["value"]="abc"}); value="12,34" in a locale expecting '.'; value="NaN"/"Infinity" (not finite); value="1.2.3"; type=num value="".

Common situations: Forcing a text column into numeric type; locale-specific number formatting (thousands separators, comma decimals) that double.TryParse under InvariantCulture rejects; passing Infinity/NaN from a computation.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/4117f1e14da2df25. Report an issue: GitHub.