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
- Pass a finite numeric literal using a period as the decimal separator (InvariantCulture format), e.g. "3.14".
- If the value may be text, use type=string instead of type=number.
- 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
- Use InvariantCulture decimal format (period separator) for numeric values.
- Reject NaN/Infinity before the call; do not pass them as numbers.
- Sanitize locale-specific separators (thousands, comma decimals) first.
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
- Unrecognized cell parent path segment '{cellSegments[1]}'. E
- Invalid cell reference: '{cellRef}'
- --prop shift={shiftVal} not valid for add cell. Use 'right'
- Cannot store '{properties.GetValueOrDefault("value") ?? prop
- Literal braces '{...}' around a formula create an Excel-reje
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/4117f1e14da2df25.
Report an issue: GitHub.