larksuite/cli · error

%s must be a number

Error message

%s must be a number

What it means

A field typed as number (float allowed) received a value that is not a JSON number at all — commonly a numeric string "3.14", a bool, or null. validationNumber(value) fails the type assertion. JSON type fidelity matters: quoted numbers are strings.

Source

Thrown at shortcuts/common/typed_binder.go:456

	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)
		}
		if constraint.Minimum != nil && number < *constraint.Minimum {
			return fmt.Errorf("%s must be at least %v", path, *constraint.Minimum)
		}
		if constraint.Maximum != nil && number > *constraint.Maximum {
			return fmt.Errorf("%s must be at most %v", path, *constraint.Maximum)
		}
		return nil
	case typedArrayShape:
		items, ok := value.([]any)
		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)

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Convert string input with strconv.ParseFloat before binding
  2. Remove quotes around numeric literals in JSON/templates
  3. For env/config sources, parse explicitly: v, err := strconv.ParseFloat(os.Getenv("RATIO"), 64)
  4. Confirm the field type via `schema`; if it is integer-typed, supply an integer instead

Example fix

// before
ratio := os.Getenv("RATIO")          // "1.5" (string)
body := map[string]any{"ratio": ratio}
// after
ratio, err := strconv.ParseFloat(os.Getenv("RATIO"), 64)
if err != nil { return err }
body := map[string]any{"ratio": ratio}
Defensive patterns

Strategy: type-guard

Validate before calling

func ensureNumber(v any) error {
    switch v.(type) {
    case float64, float32, int, int64:
        return nil
    default:
        return fmt.Errorf("expected JSON number, got %T", v)
    }
} // convert string sources first: strconv.ParseFloat

Type guard

func isJSONNumber(v any) bool {
    switch v.(type) {
    case float64, float32, int, int64:
        return true
    }
    return false
}

Try / catch

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

Prevention

When it happens

Trigger: Passing "1.5" (quoted) to a number field; shell variable interpolation quoting the value; passing null to a required number in a nested object validated by valueCompatibleWithShape.

Common situations: Reading values from env vars or CLI text input (always strings) without conversion; config files where the number was quoted; hand-built JSON templates that quote numeric fields.

Related errors


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