larksuite/cli · error
%s must be an object
Error message
%s must be an object
What it means
Object shape validation: a field declared as a typed object received a value that is not a JSON object after decoding. The type assertion to map[string]any fails and the binder reports the field path.
Source
Thrown at shortcuts/common/typed_binder.go:488
if !ok {
return fmt.Errorf("%s must be an array", path)
}
if constraint.MinItems != nil && len(items) < *constraint.MinItems {
return fmt.Errorf("%s must contain at least %d items", path, *constraint.MinItems)
}
if constraint.MaxItems != nil && len(items) > *constraint.MaxItems {
return fmt.Errorf("%s must contain at most %d items", path, *constraint.MaxItems)
}
for i, item := range items {
if err := validateJSONValueAgainstShape(item, constraint.Items, fmt.Sprintf("%s[%d]", path, i)); err != nil {
return err
}
}
return nil
case typedObjectShape:
object, ok := value.(map[string]any)
if !ok {
return fmt.Errorf("%s must be an object", path)
}
fields := make(map[string]typedValueField, len(constraint.Fields))
for _, field := range constraint.Fields {
fields[field.Name] = field
if field.Required {
if _, exists := object[field.Name]; !exists {
return fmt.Errorf("%s.%s is required", path, field.Name)
}
}
}
for name, item := range object {
field, exists := fields[name]
if !exists {
if !constraint.AdditionalProperties {
return fmt.Errorf("%s contains unknown field %q", path, name)
}
if constraint.AdditionalPropertiesShape != nil {
if err := validateJSONValueAgainstShape(item, constraint.AdditionalPropertiesShape, path+"."+name); err != nil {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Wrap the value as a JSON object with braces and quoted keys.
- Verify with --help/schema that the field is an object and inspect its declared fields.
- Quote the whole argument to survive shell brace expansion.
- Validate the JSON with a parser (jq) before passing it.
Example fix
// before
lark-cli shortcut demo --settings 'key=value'
// error: settings must be an object
// after
lark-cli shortcut demo --settings '{"key":"value"}' Defensive patterns
Strategy: type-guard
Validate before calling
value='{"a":1}'
echo "$value" | jq -e 'type=="object"' >/dev/null || { echo "expected a JSON object" >&2; exit 2; } Type guard
func isJSONObject(raw string) bool {
var v map[string]any
return json.Unmarshal([]byte(raw), &v) == nil
} Try / catch
err := cmd.Run()
var valErr *errs.ValidationError
if errors.As(err, &valErr) && strings.Contains(valErr.Error(), "must be an object") {
// fix the payload to a JSON object and retry
} Prevention
- Single-quote JSON payloads to protect braces from the shell.
- Validate with jq type=="object" before invoking.
- Confirm the field is object-shaped via schema.
- Build nested payloads by marshaling maps, not string concatenation.
When it happens
Trigger: Passing a scalar or array where a JSON object flag is expected — e.g. --settings 'foo' or --settings '[1,2]' instead of '{"key":"value"}'.
Common situations: Shell quoting mangling braces; forgetting the outer {} around key/value payloads; config files storing a stringified object without parsing; nesting mistakes (object expected, array of objects given).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/80aebe4b71f75dae.
Report an issue: GitHub.