iOfficeAI/OfficeCLI · error · ArgumentException

Cannot store '{dateText}' as date; Excel does not support da

Error message

Cannot store '{dateText}' as date; Excel does not support dates before 1900-01-01 (serial epoch is 1899-12-30). Use type=string to keep the literal text.

What it means

Excel's serial-date epoch is 1899-12-30, and dates earlier than 1900-01-01 are not representable — they round-trip as the epoch and silently mislead the user. When type=date is supplied and the parsed value is before 1900-01-01, this guard rejects it instead of silently clamping, mirroring Set's pre-1900 guard.

Source

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

                            $"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))
                            throw new ArgumentException(
                                $"Cannot store '{dateText}' as date; Excel does not support dates before 1900-01-01 " +
                                $"(serial epoch is 1899-12-30). Use type=string to keep the literal text.");
                        cell.CellValue = new CellValue(
                            ExcelDataFormatter.ToExcelSerial(dt, IsWorkbookDate1904()).ToString(System.Globalization.CultureInfo.InvariantCulture));
                    }
                    else if (!string.IsNullOrEmpty(dateText))
                    {
                        // BUG-FIX(B10): if user said type=date but the value isn't
                        // parseable, refuse to leave a date-shaped string in a
                        // numeric-styled cell — that produces invalid OOXML.
                        throw new ArgumentException(
                            $"Cannot store '{dateText}' as date; value must be ISO 8601 (yyyy-MM-dd) " +
                            $"and represent a real calendar day. Use type=string to keep the literal text.");
                    }
                    // Apply a default date number format unless the caller
                    // already supplied one — matches Set's type=date guard.
                    if (!properties.ContainsKey("numberformat")
                        && !properties.ContainsKey("numfmt")

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Store pre-1900 dates as text with type=string, since Excel cannot represent them as serial dates.
  2. Filter or transform pre-1900 values before the call (e.g. clamp to a sentinel string like 'pre-1900').
  3. Validate the year >= 1900 when type=date is intended.

Example fix

// before
handler.Add("/Sheet1/A1", "cell", null, new() { ["type"] = "date", ["value"] = "1850-01-01" });
// after
handler.Add("/Sheet1/A1", "cell", null, new() { ["type"] = "string", ["value"] = "1850-01-01" });
Defensive patterns

Strategy: validation

Validate before calling

if (props.GetValueOrDefault("type")?.Equals("date", StringComparison.OrdinalIgnoreCase) == true)
{
    if (DateTime.TryParse(props.GetValueOrDefault("value"), out var dt) && dt < new DateTime(1900,1,1))
        throw new ArgumentException("date is before Excel's 1900-01-01 epoch");
}

Type guard

static bool IsExcelRepresentableDate(string? s) =>
    DateTime.TryParse(s, out var dt) && dt >= new DateTime(1900, 1, 1);

Try / catch

try { h.Add(parentPath, "cell", pos, props); }
catch (ArgumentException ex) when (ex.Message.Contains("before 1900-01-01"))
{ /* store as type=string instead */ }

Prevention

When it happens

Trigger: Add("/Sheet1/A1","cell",pos,{["type"]="date",["value"]="1899-12-31"}); value="1850-01-01"; value="1066-10-14"; any ISO date that TryParseIsoDateFlexible parses to a DateTime < 1900-01-01.

Common situations: Historical data (birth dates before 1900, genealogical records, archival dates); importing a dataset with mixed-era dates; a default/placeholder sentinel date like 0001-01-01.

Related errors


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