github/copilot-sdk · error · IllegalArgumentException

Parameter ' + param.name() + ' expected a numeric value for…

Error message

Parameter ' + param.name() + ' expected a numeric value for OptionalLong, got: + raw.getClass().getSimpleName()

What it means

Thrown by ParamCoercion.coerce when an RPC parameter declared as java.util.OptionalLong receives a value that is not a java.lang.Number. The coercion attempts ((Number) raw).longValue() and wraps the resulting ClassCastException into an IllegalArgumentException naming the parameter and the offending runtime class. This guards tool parameters that require an integral numeric value (possibly absent).

Solutions

  1. Pass a java.lang.Number (Long/Integer/BigInteger) for OptionalLong parameters, or omit the key / pass null for empty Optional
  2. Convert string inputs first: OptionalLong.of(Long.parseLong(String.valueOf(raw))) before invoking the tool
  3. Check the tool schema (ParamSchema.buildSchema) for the parameter's declared type and match it in the client payload
  4. Catch IllegalArgumentException around the tool invocation and log param.name() plus raw.getClass() to fix the caller

Example fix

// before
Map<String,Object> args = Map.of("count", "42");
tool.invoke(args); // throws: expected a numeric value for OptionalLong, got: String
// after
Map<String,Object> args = Map.of("count", 42L);
tool.invoke(args);
Defensive patterns

Strategy: type-guard

Validate before calling

if (raw instanceof Number) { args.put("count", ((Number) raw).longValue()); }

Type guard

boolean isNumber(Object v) { return v instanceof Number; }

Try / catch

try { tool.invoke(args); } catch (IllegalArgumentException e) { if (e.getMessage().contains("OptionalLong")) { /* convert string to Long and retry */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling a tool whose @Param is OptionalLong and passing a raw value whose runtime class is not a Number — e.g. a String like "42", a Boolean, or a Map/List (typically from deserialized JSON that was not pre-typed).

Common situations: Clients send long parameters as JSON strings; a caller builds argument maps by hand and puts String instead of Long; a JSON binder leaves numbers as String or BigInteger-derived types when config disables numeric typing.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/7e6a4f512c9c94a4. Report an issue: GitHub.

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/rpc/ParamCoercion.java:90

            }
        }

        Class<T> type = param.type();

        // Handle Optional* types explicitly before delegating to ObjectMapper
        if (type == java.util.OptionalInt.class) {
            try {
                return (T) java.util.OptionalInt.of(((Number) raw).intValue());
            } catch (ClassCastException ex) {
                throw new IllegalArgumentException("Parameter '" + param.name()
                        + "' expected a numeric value for OptionalInt, got: " + raw.getClass().getSimpleName(), ex);
            }
        }
        if (type == java.util.OptionalLong.class) {
            try {
                return (T) java.util.OptionalLong.of(((Number) raw).longValue());
            } catch (ClassCastException ex) {
                throw new IllegalArgumentException("Parameter '" + param.name()
                        + "' expected a numeric value for OptionalLong, got: " + raw.getClass().getSimpleName(), ex);
            }
        }
        if (type == java.util.OptionalDouble.class) {
            try {
                return (T) java.util.OptionalDouble.of(((Number) raw).doubleValue());
            } catch (ClassCastException ex) {
                throw new IllegalArgumentException("Parameter '" + param.name()
                        + "' expected a numeric value for OptionalDouble, got: " + raw.getClass().getSimpleName(), ex);
            }
        }

        try {
            return mapper.convertValue(raw, type);
        } catch (IllegalArgumentException ex) {
            throw new IllegalArgumentException(
                    "Failed to coerce parameter '" + param.name() + "' to type " + type.getSimpleName(), ex);
        }

View on GitHub (pinned to cd8cf15dc3)