iOfficeAI/OfficeCLI · warning · JsonException

Expected object or ["key=value"] array for props

Error message

Expected object or ["key=value"] array for props

What it means

JsonException from LenientStringDictionaryConverter.Read when the props value is neither an array nor an object — a bare scalar at the props position (number, boolean, string, or a top-level null that wasn't handled). The converter accepts only StartArray or StartObject, so any other leading token is rejected.

Source

Thrown at src/officecli/BatchTypes.cs:36

        // item. Before this, batch props was object-only and every array-form
        // batch failed with "Expected object for props" — observed as a 100%
        // batch-failure for models that (correctly) reused the single-command
        // props shape. Lenient split on the first '=' matches McpServer.ParseProps.
        if (reader.TokenType == JsonTokenType.StartArray)
        {
            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndArray) return dict;
                if (reader.TokenType != JsonTokenType.String)
                    throw new JsonException("Expected \"key=value\" string in props array");
                var kv = reader.GetString()!;
                var eq = kv.IndexOf('=');
                if (eq > 0) dict[kv[..eq]] = kv[(eq + 1)..];  // skip malformed, as ParseProps does
            }
            throw new JsonException("Unexpected end of JSON");
        }
        if (reader.TokenType != JsonTokenType.StartObject)
            throw new JsonException("Expected object or [\"key=value\"] array for props");
        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject) return dict;
            if (reader.TokenType != JsonTokenType.PropertyName)
                throw new JsonException("Expected property name");
            var key = reader.GetString()!;
            reader.Read();
            var value = reader.TokenType switch
            {
                JsonTokenType.String => reader.GetString()!,
                JsonTokenType.Number => reader.TryGetInt64(out var l) ? l.ToString() : reader.GetDouble().ToString(),
                JsonTokenType.True => "true",
                JsonTokenType.False => "false",
                JsonTokenType.Null => "",
                _ => throw new JsonException($"Unexpected token {reader.TokenType} for prop value '{key}'")
            };
            dict[key] = value;
        }

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Provide props as an object {key:'value'} or an array ["key=value"].
  2. If you only have one kv-pair as a string, wrap it: props: ['text=hi'] or props: { text: 'hi' }.
  3. Omit props entirely when there are none, rather than sending a scalar.

Example fix

// before: { command:'set', props: 'text=hi' }
// after:  { command:'set', props: ['text=hi'] }  // or props: { text: 'hi' }
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure props is an object or a string array before sending
function validProps(p) {
  if (p == null) return true;
  if (Array.isArray(p)) return p.every(x => typeof x === 'string');
  return typeof p === 'object';
}

Type guard

function isPropsShape(p) {
  if (p == null) return true;
  if (Array.isArray(p)) return p.every(x => typeof x === 'string');
  return p !== null && typeof p === 'object';
}

Prevention

When it happens

Trigger: "props": 42, "props": true, "props": "text=hi" (a string, not an array/object), or "props": <some other scalar>. A literal null is returned as null before this check only when it is the leading token.

Common situations: An agent that supplies props as a single string instead of an object/array; a numeric flag mistakenly assigned to props; a schema drift where props became a scalar.

Related errors


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