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
- Provide props as an object {key:'value'} or an array ["key=value"].
- If you only have one kv-pair as a string, wrap it: props: ['text=hi'] or props: { text: 'hi' }.
- 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
- Never put a scalar (number/boolean/string) at the props position.
- Omit props when empty rather than sending null/scalar.
- Validate item shape with isPropsShape() in test builds.
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
- Expected "key=value" string in props array
- Unexpected token {reader.TokenType} for prop value '{key}'
- Unexpected end of JSON
- Expected property name
- Expected StartObject for BatchItem
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/50724694e690427d.
Report an issue: GitHub.