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

  1. Pass a real boolean (true/false) instead of a quoted string or number
  2. Unquote the value in templates/scripts: use true not "true"
  3. If the value originates from config, parse it to bool before binding
  4. 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

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.