larksuite/cli · error
%s must be a boolean
Error message
%s must be a boolean
What it means
A field whose schema is a boolean received a JSON value that is not bool (e.g. the string "true" or the number 1). validateJSONValueAgainstShape type-asserts value.(bool) and fails. JSON does not coerce between strings and booleans, so the literal type must be bool.
Source
Thrown at shortcuts/common/typed_binder.go:432
text, ok := value.(string)
if !ok {
return fmt.Errorf("%s must be a string", path)
}
length := len([]rune(text))
if constraint.MinLength != nil && length < *constraint.MinLength {
return fmt.Errorf("%s must contain at least %d characters", path, *constraint.MinLength)
}
if constraint.MaxLength != nil && length > *constraint.MaxLength {
return fmt.Errorf("%s must contain at most %d characters", path, *constraint.MaxLength)
}
if len(constraint.Enum) > 0 && !slices.Contains(constraint.Enum, text) {
return fmt.Errorf("%s must be one of: %s", path, strings.Join(constraint.Enum, ", "))
}
return nil
case typedBooleanShape:
boolean, ok := value.(bool)
if !ok {
return fmt.Errorf("%s must be a boolean", path)
}
if len(constraint.Enum) > 0 && !slices.Contains(constraint.Enum, boolean) {
return fmt.Errorf("%s has an unsupported boolean value", path)
}
return nil
case typedIntegerShape:
number, ok := validationInteger(value)
if !ok {
return fmt.Errorf("%s must be an integer", path)
}
if constraint.Minimum != nil && number < *constraint.Minimum {
return fmt.Errorf("%s must be at least %d", path, *constraint.Minimum)
}
if constraint.Maximum != nil && number > *constraint.Maximum {
return fmt.Errorf("%s must be at most %d", path, *constraint.Maximum)
}
if len(constraint.Enum) > 0 && !slices.Contains(constraint.Enum, number) {
return fmt.Errorf("%s has an unsupported integer value", path)View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Pass a real boolean (true/false) instead of a quoted string or number
- Unquote the value in templates/scripts: use true not "true"
- If the value originates from config, parse it to bool before binding
- Confirm the field really is boolean via `schema`; if it accepts a string enum, use the string form
Example fix
// before
body := fmt.Sprintf(`{"enabled": "%v"}`, enabled) // "enabled": "true"
// after
body := fmt.Sprintf(`{"enabled": %t}`, enabled) // "enabled": true Defensive patterns
Strategy: type-guard
Validate before calling
func ensureBool(v any) error {
if _, ok := v.(bool); !ok {
return fmt.Errorf("expected JSON boolean, got %T", v)
}
return nil
} Type guard
func isJSONBool(v any) bool { _, ok := v.(bool); return ok } Try / catch
if err := bind(field, v); err != nil {
if strings.Contains(err.Error(), "must be a boolean") {
return fmt.Errorf("field %s requires literal true/false, not a quoted string: %w", field, err)
}
return err
} Prevention
- Use typed structs (bool fields) instead of map[string]any for request bodies
- In templates, emit %t not "%v" for boolean fields
- Parse config flags with strconv.ParseBool instead of passing raw strings
- Never quote true/false when building JSON by hand
When it happens
Trigger: Passing "true"/"false" (quoted strings) where a JSON boolean is required; supplying 0/1 instead of true/false in a nested object or JSON body field bound through validateCompiledValue.
Common situations: Building JSON bodies by hand or via shell interpolation where booleans get quoted; configuration files where flags are stored as strings; converting from a language where 0/1 are truthy values.
Related errors
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/7e907d87c2be7cf4.
Report an issue: GitHub.