iOfficeAI/OfficeCLI · error · System.ArgumentException

'row' property is required for rowbreak

Error message

'row' property is required for rowbreak

What it means

Thrown by AddRowBreak when neither the row nor the index property is present in the properties dictionary. The code uses GetValueOrDefault("row") ?? GetValueOrDefault("index") and throws if both are null. A row break requires a target row number, so omitting it is unrecoverable.

Source

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

    {
        var index = position?.Index;
        // Route to rowbreak or colbreak based on properties
        if (properties.ContainsKey("col") || properties.ContainsKey("column"))
            return Add(parentPath, "colbreak", position, properties);
        return Add(parentPath, "rowbreak", position, properties);
    }

    private string AddRowBreak(string parentPath, string type, InsertPosition? position, Dictionary<string, string> properties)
    {
        var index = position?.Index;
        var rbSegments = parentPath.TrimStart('/').Split('/', 2);
        var rbSheetName = rbSegments[0];
        var rbWorksheet = FindWorksheet(rbSheetName)
            ?? throw new ArgumentException($"Sheet not found: {rbSheetName}");
        var rbWs = GetSheet(rbWorksheet);

        var rbRowIdx = uint.Parse(properties.GetValueOrDefault("row") ?? properties.GetValueOrDefault("index")
            ?? throw new ArgumentException("'row' property is required for rowbreak"));
        // A break id of 0 or beyond the grid fails the schema's Min/Max
        // constraints — reject up front instead of writing invalid OOXML.
        if (rbRowIdx < 1 || rbRowIdx > 1048576)
            throw new ArgumentException(
                $"Invalid 'row' value: '{rbRowIdx}'. Row breaks must be between 1 and 1048576.");

        var rowBreaks = rbWs.GetFirstChild<RowBreaks>();
        if (rowBreaks == null)
        {
            rowBreaks = new RowBreaks();
            rbWs.AppendChild(rowBreaks);
        }
        // Optional restricted column span (min/max) — mirrors the Set path so a
        // dump-emitted `add rowbreak row=N min=.. max=..` reproduces a
        // non-full-width break. Defaults to full width (max 16383) when absent.
        var rbBreak = new Break { Id = rbRowIdx, Max = 16383u, ManualPageBreak = true };
        if (properties.TryGetValue("min", out var rbMinS) && uint.TryParse(rbMinS, out var rbMin))
            rbBreak.Min = rbMin;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Add a row property: properties["row"]="5".
  2. The index property is accepted as an alias, so properties["index"]="5" works too.
  3. If you meant a column break, use type=colbreak with col= instead.

Example fix

// before
handler.Add("/Sheet1", "rowbreak", null, new() { ["min"] = "1" });

// after
handler.Add("/Sheet1", "rowbreak", null, new() { ["row"] = "5", ["min"] = "1" });
Defensive patterns

Strategy: validation

Validate before calling

if (!props.ContainsKey("row") && !props.ContainsKey("index"))
    throw new InvalidOperationException("rowbreak requires 'row' or 'index'");
handler.Add("/Sheet1", "rowbreak", null, props);

Type guard

static bool HasRowbreakTarget(IReadOnlyDictionary<string,string> p)
    => p.ContainsKey("row") || p.ContainsKey("index");

Prevention

When it happens

Trigger: Add type=rowbreak with a properties dictionary that has neither "row" nor "index" (e.g. only min/max, or empty). Passing "row" with an empty string value: GetValueOrDefault returns the empty string, which then fails uint.Parse with a FormatException (a different error), not this one. This throw specifically needs the key absent entirely.

Common situations: User copies a colbreak command and forgets to change the property from col to row. Script builds properties conditionally and both branches are skipped. Assuming index defaults to the position's Index (it does not for rowbreak).

Related errors


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