iOfficeAI/OfficeCLI · error · ArgumentException

'set' command requires 'props' field with at least one key=v

Error message

'set' command requires 'props' field with at least one key=value. Got empty/missing props.

What it means

Thrown by ExecuteBatchItem for a batch "set" step that has a path but empty or missing props. Previously this was a silent no-op reported as success, hiding caller mistakes (forgotten props field, a key promoted to the root, an empty generated dict). It now fails fast to match the standalone set command's behavior.

Source

Thrown at src/officecli/CommandBuilder.cs:988

                        ? OfficeCli.Handlers.ExcelHandler.ResolveCellAttributeAlias : null;
                var (results, warnings) = OfficeCli.Core.AttributeFilter.FilterSelector(selector, handler.Query, keyResolver);
                if (item.Text is { } textFilter && !string.IsNullOrEmpty(textFilter))
                    // MatchesTextFilter (not plain Contains) so a batch query
                    // text filter honours r"regex" like the CLI and resident do.
                    results = results.Where(n => n.Text != null && OfficeCli.Core.AttributeFilter.MatchesTextFilter(n.Text, textFilter)).ToList();
                foreach (var w in warnings) Console.Error.WriteLine(w.Message);
                return OfficeCli.Core.OutputFormatter.FormatNodes(results, format);
            }
            case "set":
            {
                if (string.IsNullOrEmpty(item.Path))
                    throw new ArgumentException("'set' command requires 'path' field. Example: {\"command\": \"set\", \"path\": \"/slide[1]\", \"props\": {\"bold\": \"true\"}}");
                // Match standalone `set` rejection of empty/missing props — a
                // batch step with no props is a no-op that previously reported
                // success, hiding caller mistakes (forgotten props field,
                // misspelled key promoted to root, etc.).
                if (props.Count == 0)
                    throw new ArgumentException("'set' command requires 'props' field with at least one key=value. Got empty/missing props.");
                var path = item.Path;
                OfficeCli.Core.MutationSelectorGuard.EnsureScoped(path, "set");
                // Shared core: apply + prop-autocorrect + categorise. Identical
                // across CLI / batch / MCP / resident; only the output below is
                // batch-specific.
                var (applied, unsupported, autoCorrected) = ApplySetWithCorrection(handler, path, props);
                var parts = new List<string>();
                if (autoCorrected.Count > 0)
                    parts.Add("Auto-corrected: " + string.Join(", ", autoCorrected.Select(ac => $"{ac.Original}→{ac.Corrected}")));
                if (applied.Count > 0)
                {
                    var msg = $"Updated {path}: {string.Join(", ", applied.Select(kv => $"{kv.Key}={kv.Value}"))}";
                    if (props.ContainsKey("find"))
                    {
                        var matched = handler switch
                        {
                            OfficeCli.Handlers.WordHandler wh => wh.LastFindMatchCount,
                            OfficeCli.Handlers.PowerPointHandler ph => ph.LastFindMatchCount,

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Supply at least one key=value in props: {"bold":"true"}.
  2. If no props apply, skip the set step entirely rather than emitting an empty one.
  3. Guard the generator: only emit a set step when the props dict is non-empty.
  4. Check for misspelled prop keys that were meant to be inside props.

Example fix

// before
{"command":"set","path":"/slide[1]","props":{}}
// after
{"command":"set","path":"/slide[1]","props":{"bold":"true"}}
Defensive patterns

Strategy: validation

Validate before calling

if ((item.Props?.Count ?? 0) == 0)
    throw new ArgumentException("'set' requires at least one prop");
// or skip emitting the step when props is empty

Type guard

static bool IsValidSetItem(BatchItem i)
    => !string.IsNullOrEmpty(i.Path) && (i.Props?.Count ?? 0) > 0;

Prevention

When it happens

Trigger: {"command":"set","path":"/slide[1]","props":{}}; {"command":"set","path":"/slide[1]"} with no props field; props built dynamically that produced an empty dictionary.

Common situations: Props field misspelled or promoted to the root object; a generator that filtered out all keys; conditional logic that left props empty; an LLM that emitted path but omitted props.

Related errors


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