{"record":{"id":"7e6a4f512c9c94a4","repo":"github/copilot-sdk","slug":"parameter-param-name-expected-a-numeric-7e6a4f","errorCode":null,"errorMessage":"Parameter ' + param.name() + ' expected a numeric value for OptionalLong, got: + raw.getClass().getSimpleName()","messagePattern":"Parameter ' \\+ param\\.name\\(\\) \\+ ' expected a numeric value for OptionalLong, got: \\+ raw\\.getClass\\(\\)\\.getSimpleName\\(\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/rpc/ParamCoercion.java","lineNumber":90,"sourceCode":"            }\n        }\n\n        Class<T> type = param.type();\n\n        // Handle Optional* types explicitly before delegating to ObjectMapper\n        if (type == java.util.OptionalInt.class) {\n            try {\n                return (T) java.util.OptionalInt.of(((Number) raw).intValue());\n            } catch (ClassCastException ex) {\n                throw new IllegalArgumentException(\"Parameter '\" + param.name()\n                        + \"' expected a numeric value for OptionalInt, got: \" + raw.getClass().getSimpleName(), ex);\n            }\n        }\n        if (type == java.util.OptionalLong.class) {\n            try {\n                return (T) java.util.OptionalLong.of(((Number) raw).longValue());\n            } catch (ClassCastException ex) {\n                throw new IllegalArgumentException(\"Parameter '\" + param.name()\n                        + \"' expected a numeric value for OptionalLong, got: \" + raw.getClass().getSimpleName(), ex);\n            }\n        }\n        if (type == java.util.OptionalDouble.class) {\n            try {\n                return (T) java.util.OptionalDouble.of(((Number) raw).doubleValue());\n            } catch (ClassCastException ex) {\n                throw new IllegalArgumentException(\"Parameter '\" + param.name()\n                        + \"' expected a numeric value for OptionalDouble, got: \" + raw.getClass().getSimpleName(), ex);\n            }\n        }\n\n        try {\n            return mapper.convertValue(raw, type);\n        } catch (IllegalArgumentException ex) {\n            throw new IllegalArgumentException(\n                    \"Failed to coerce parameter '\" + param.name() + \"' to type \" + type.getSimpleName(), ex);\n        }","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/rpc/ParamCoercion.java#L72-L108","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Pass a java.lang.Number (Long/Integer/BigInteger) for OptionalLong parameters, or omit the key / pass null for empty Optional","Convert string inputs first: OptionalLong.of(Long.parseLong(String.valueOf(raw))) before invoking the tool","Check the tool schema (ParamSchema.buildSchema) for the parameter's declared type and match it in the client payload","Catch IllegalArgumentException around the tool invocation and log param.name() plus raw.getClass() to fix the caller"],"exampleFix":"// before\nMap<String,Object> args = Map.of(\"count\", \"42\");\ntool.invoke(args); // throws: expected a numeric value for OptionalLong, got: String\n// after\nMap<String,Object> args = Map.of(\"count\", 42L);\ntool.invoke(args);","handlingStrategy":"type-guard","validationCode":"if (raw instanceof Number) { args.put(\"count\", ((Number) raw).longValue()); }","typeGuard":"boolean isNumber(Object v) { return v instanceof Number; }","tryCatchPattern":"try { tool.invoke(args); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"OptionalLong\")) { /* convert string to Long and retry */ } else { throw e; } }","preventionTips":["Match JSON types exactly to the declared parameter type (unquoted numbers)","Coerce string inputs to Long before invoking tools","Validate payloads against the tool's generated schema"],"tags":["java","rpc","type-mismatch","parameters"],"backgroundTag":"type-mismatch","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}