{"record":{"id":"f97d31f350cc51ea","repo":"github/copilot-sdk","slug":"unsupported-json-rpc-params-shape-paramsprop-val","errorCode":null,"errorMessage":"Unsupported JSON-RPC params shape '{paramsProp.ValueKind}' for handler with positional parameters.","messagePattern":"Unsupported JSON-RPC params shape '(.+?)' for handler with positional parameters\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/JsonRpc.cs","lineNumber":680,"sourceCode":"                {\n                    invokeArgs[i] = cancellationToken;\n                }\n                else if (parameters[i].Name is { } paramName &&\n                         TryGetPropertyCaseInsensitive(paramsProp, paramName, out var valueProp))\n                {\n                    invokeArgs[i] = valueProp.Deserialize(_serializerOptions.GetTypeInfo(parameters[i].ParameterType));\n                }\n                else\n                {\n                    invokeArgs[i] = parameters[i].HasDefaultValue ? parameters[i].DefaultValue : null;\n                }\n            }\n        }\n        else\n        {\n            // Missing/null `params` for a handler with required positional parameters is a\n            // protocol violation. Surface it as an error rather than silently filling defaults.\n            throw new InvalidOperationException(\n                $\"Unsupported JSON-RPC params shape '{paramsProp.ValueKind}' for handler with positional parameters.\");\n        }\n\n        // Invoke\n        var result = registration.Handler.DynamicInvoke(invokeArgs);\n\n        // Handlers return one of: a synchronous value, Task (void async), or ValueTask<T>.\n        if (result is Task task)\n        {\n            // Task<T> handlers are not supported — use ValueTask<T> for results.\n            Debug.Assert(!task.GetType().IsGenericType, \"Task<T> handlers are not supported; use ValueTask<T>.\");\n            await task.ConfigureAwait(false);\n            return null;\n        }\n\n        if (result is not null && registration.ValueTaskAsTaskMethod is { } valueTaskAsTaskMethod)\n        {\n            var asTask = (Task)valueTaskAsTaskMethod.Invoke(result, null)!;","sourceCodeStart":662,"sourceCodeEnd":698,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/JsonRpc.cs#L662-L698","documentation":"InvokeHandlerAsync dispatches JSON-RPC requests to registered handlers. When a handler declares required positional parameters, the request's `params` must be a JSON array (positional) or object (by-name); anything else — including missing/null params or a scalar/string params value — is a protocol violation, so the library throws instead of silently filling in default values.","triggerScenarios":"Sending a JSON-RPC request whose `params` is absent, null, a bare string/number/boolean, while the target handler was registered with required positional parameters (e.g. calling a method with `\"params\": null` or omitting params entirely).","commonSituations":"Hand-rolled JSON-RPC clients omitting params for no-arg-looking methods; protocol proxies forwarding notifications; protocol version mismatches where a caller assumes params are optional; malformed requests from LLM/tool harnesses generating raw JSON.","solutions":["Include a `params` value in the request matching the handler signature: a JSON array of positional arguments or an object keyed by parameter name.","If the method truly takes no parameters, register the handler without required positional parameters (e.g. accept a parameterless delegate or use a params object/CancellationToken-only signature).","Validate the outgoing request on the client side: ensure params is an array or object before sending.","Catch InvalidOperationException in InvokeHandlerAsync callers and return a JSON-RPC Invalid Params error (-32602) instead of crashing."],"exampleFix":"// before\nawait rpc.InvokeAsync(\"add\", (object?)null);\n\n// after\nawait rpc.InvokeAsync(\"add\", new object[] { 1, 2 });","handlingStrategy":"validation","validationCode":"if (params is not (JsonElement.ValueKind.Array or JsonElement.ValueKind.Object))\n    throw new ArgumentException(\"JSON-RPC params must be an array or object for positional handlers\", nameof(params));","typeGuard":"static bool HasValidParamsShape(JsonElement p) => p.ValueKind is JsonValueKind.Array or JsonValueKind.Object;","tryCatchPattern":"try { await rpc.InvokeAsync(method, args); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Unsupported JSON-RPC params shape\"))\n{ return JsonRpcError.InvalidParams(ex.Message); }","preventionTips":["Always serialize params as an array or object in JSON-RPC requests","Validate request shape client-side before sending","Match handler signatures to the params shape you send"],"tags":["json-rpc","protocol-violation","deserialization","dotnet"],"backgroundTag":"invalid-argument-format","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"}