{"record":{"id":"d9790715d7723176","repo":"github/copilot-sdk","slug":"expected-json-object-for-params-of-single-object","errorCode":null,"errorMessage":"Expected JSON object for `params` of single-object-param handler; got '{paramsProp.ValueKind}'.","messagePattern":"Expected JSON object for `params` of single-object-param handler; got '(.+?)'\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/JsonRpc.cs","lineNumber":616,"sourceCode":"            }\n        }\n    }\n\n    private async ValueTask<object?> InvokeHandlerAsync(MethodRegistration registration, JsonElement paramsProp, CancellationToken cancellationToken)\n    {\n        var parameters = registration.Parameters;\n\n        // Build argument list\n        var invokeArgs = new object?[parameters.Length];\n\n        if (registration.SingleObjectParam)\n        {\n            // Single-object deserialization: entire `params` → first parameter.\n            // Every singleObjectParam handler has shape (TRequest, CancellationToken),\n            // so `params` must be a JSON object.\n            if (paramsProp.ValueKind != JsonValueKind.Object)\n            {\n                throw new InvalidOperationException(\n                    $\"Expected JSON object for `params` of single-object-param handler; got '{paramsProp.ValueKind}'.\");\n            }\n\n            for (int i = 0; i < parameters.Length; i++)\n            {\n                if (parameters[i].ParameterType == typeof(CancellationToken))\n                {\n                    invokeArgs[i] = cancellationToken;\n                }\n                else if (i == 0)\n                {\n                    invokeArgs[i] = paramsProp.Deserialize(_serializerOptions.GetTypeInfo(parameters[i].ParameterType));\n                }\n            }\n        }\n        else if (paramsProp.ValueKind == JsonValueKind.Array)\n        {\n            // Positional parameters. Optional params (with defaults) are filled when absent.","sourceCodeStart":598,"sourceCodeEnd":634,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/JsonRpc.cs#L598-L634","documentation":"InvokeHandlerAsync throws InvalidOperationException when a handler registered as taking a single object parameter receives a `params` value that is not a JSON object (e.g. array, string, or null). These handlers deserialize the entire params object into the first parameter, so a non-object shape cannot be bound.","triggerScenarios":"Client sends params as an array (positional style) or omits params (ValueKind Undefined/Null) for a method whose handler is a (TRequest, CancellationToken) single-object handler.","commonSituations":"Client SDK using positional parameters while server method expects named fields; a request built by hand with \"params\": [] or no params; protocol mismatch between client and server versions.","solutions":["Send params as a JSON object with the field names the TRequest type expects.","Omit positional-array params; convert them to named-object params on the client.","Ensure client and server agree on the method's request schema (update the client SDK).","For optional params, send an empty object rather than null/omitted params if the handler requires an object."],"exampleFix":"// before\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":[]}\n// after\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"capabilities\":{},\"clientInfo\":{\"name\":\"x\",\"version\":\"1\"}}}","handlingStrategy":"validation","validationCode":"static JsonNode? ValidateParams(JsonElement? raw) =>\n    raw is { ValueKind: JsonValueKind.Object } el ? JsonNode.Parse(el.GetRawText())\n    : throw new ArgumentException(\"params must be a JSON object for this method\");","typeGuard":"bool IsJsonObjectParams(JsonElement p) => p.ValueKind == JsonValueKind.Object;","tryCatchPattern":"try { result = await rpc.InvokeAsync(method, requestObj, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"single-object-param handler\")) {\n    logger.LogError(ex, \"Client sent non-object params for {Method}\", method);\n    return JsonRpcError.InvalidParams(ex.Message);\n}","preventionTips":["Send named-object params, never positional arrays, for object-param methods","Generate clients from the same schema as the server handlers","Send an empty object when all params are optional","Add conformance tests covering params shapes per method"],"tags":["jsonrpc","params-shape","deserialization","protocol"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}