larksuite/cli · error

%s must be an integer

Error message

%s must be an integer

What it means

A field typed as integer received a JSON number that is not an integer — typically a float like 3.5, or a JSON number decoded as float64 without integral value. validationInteger(value) rejects it before constraint checks. Note: an integral float such as 3.0 may also be rejected depending on validationInteger, since JSON decoding yields float64.

Source

Thrown at shortcuts/common/typed_binder.go:441

			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)
		}
		return nil
	case typedNumberShape:
		number, ok := validationNumber(value)
		if !ok {
			return fmt.Errorf("%s must be a number", path)
		}
		if len(constraint.Enum) > 0 && !slices.Contains(constraint.Enum, number) {
			return fmt.Errorf("%s has an unsupported number value", path)

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Round or floor the value to a whole number before passing it
  2. If the source is a string, convert it to an integer (and keep it unquoted in JSON)
  3. Check `schema` for the field's type; use the number-typed field if fractions are intended
  4. Beware float64 artifacts: compute with integers where possible

Example fix

// before
size := total / 2 // 2.5 on odd totals
// after
size := total / 2
if total%2 != 0 { size = (total+1)/2 } // keep it integral
// or: size := int(math.Ceil(float64(total)/2))
Defensive patterns

Strategy: validation

Validate before calling

func ensureIntegral(v any) error {
    switch n := v.(type) {
    case int, int64:
        return nil
    case float64:
        if n != math.Trunc(n) {
            return fmt.Errorf("%v is not an integer", n)
        }
        return nil
    default:
        return fmt.Errorf("expected integer, got %T", v)
    }
}

Type guard

func isIntegral(v any) bool {
    n, ok := v.(float64)
    return ok && n == math.Trunc(n)
}

Try / catch

if err := bind(field, v); err != nil {
    if strings.Contains(err.Error(), "must be an integer") {
        return fmt.Errorf("field %s needs a whole number; got %v: %w", field, v, err)
    }
    return err
}

Prevention

When it happens

Trigger: Passing 1.5 to an integer field; supplying a computed value like size/2 that yields a fractional number; passing a numeric string "42" (not a number at all) validated through validateCompiledValue.

Common situations: Doing arithmetic in shell/scripts that produces decimals; copying float values from other APIs (page sizes, durations in seconds); YAML/JSON configs where IDs were quoted or written with decimals.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/3acde85d9a0449c0. Report an issue: GitHub.