iOfficeAI/OfficeCLI · error · ArgumentException

Invalid cell 'type' value '{cellType}'. Valid types: string,

Error message

Invalid cell 'type' value '{cellType}'. Valid types: string, number, boolean, date, error, richtext.

What it means

The cell type switch accepts a fixed token set: string/str, number/num, boolean/bool, date, error/err, and richtext/rich. The switch's default arm throws for any unrecognized type token, mirroring Set's accepted tokens (CONSISTENCY(cell-type-parity)) so Add and Set accept the same vocabulary.

Source

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

                        $"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.");
                cell.DataType = cellType.ToLowerInvariant() switch
                {
                    "string" or "str" => new EnumValue<CellValues>(CellValues.String),
                    "number" or "num" => null,
                    "boolean" or "bool" => new EnumValue<CellValues>(CellValues.Boolean),
                    // CONSISTENCY(cell-type-parity): Bug #4 — Add must accept
                    // the same type tokens as Set (ExcelHandler.Set.cs line 1105).
                    // Dates are stored as numeric OADate, so DataType stays null;
                    // the date-shaped cell value serialization and default
                    // numberformat are applied right after this switch.
                    "date" => null,
                    // CE16 — accept `type=error value="#N/A"|"#DIV/0!"|...` →
                    // emits <x:c t="e"><x:v>#N/A</x:v></x:c>. Standard
                    // Excel error tokens: #N/A, #DIV/0!, #REF!, #NAME?,
                    // #NULL!, #NUM!, #VALUE!, #GETTING_DATA.
                    "error" or "err" => new EnumValue<CellValues>(CellValues.Error),
                    _ => throw new ArgumentException($"Invalid cell 'type' value '{cellType}'. Valid types: string, number, boolean, date, error, richtext.")
                };
                // Convert boolean string values to OOXML-compliant 1/0
                if (cellType.Equals("boolean", StringComparison.OrdinalIgnoreCase) || cellType.Equals("bool", StringComparison.OrdinalIgnoreCase))
                {
                    var boolText = cell.CellValue?.Text?.Trim().ToLowerInvariant();
                    if (boolText == "true" || boolText == "yes" || boolText == "1")
                        cell.CellValue = new CellValue("1");
                    else if (boolText == "false" || boolText == "no" || boolText == "0")
                        cell.CellValue = new CellValue("0");
                    else if (!string.IsNullOrEmpty(boolText))
                        // A t="b" cell whose value isn't 0/1 makes real Excel
                        // refuse the whole file (0x800A03EC). Reject up front,
                        // 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=

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use one of the accepted tokens: string (or str), number (or num), boolean (or bool), date, error (or err), richtext (or rich).
  2. For free text use string/str; for numbers use number/num; for error literals use error with value=#N/A etc.
  3. Rich text is a separate branch (type=richtext/rich triggers ApplyRichTextToCell) and is not part of this switch's default error.

Example fix

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

Strategy: type-guard

Validate before calling

static readonly HashSet<string> CellTypes = new(StringComparer.OrdinalIgnoreCase)
{"string","str","number","num","boolean","bool","date","error","err","richtext","rich"};
if (props.TryGetValue("type", out var t) && !CellTypes.Contains(t))
    throw new ArgumentException($"Unsupported cell type: {t}");
h.Add(parentPath, "cell", pos, props);

Type guard

static bool IsValidCellType(string? t) =>
    t?.ToLowerInvariant() is "string" or "str" or "number" or "num" or "boolean" or "bool"
    or "date" or "error" or "err" or "richtext" or "rich";

Try / catch

try { h.Add(parentPath, "cell", pos, props); }
catch (ArgumentException ex) when (ex.Message.Contains("Invalid cell 'type' value"))
{ /* map to the accepted token set, e.g. text->string, int->number */ }

Prevention

When it happens

Trigger: Add("/Sheet1/A1","cell",pos,{["type"]="int"}); type="text" (use 'string' or 'str'); type="float" (use 'number' or 'num'); type="datetime" (use 'date'); type="bool2".

Common situations: Using language-native type names (int, float, text) instead of the OOXML-oriented token set; expecting 'datetime' when only 'date' is accepted; a typo in the type token.

Related errors


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