{"record":{"id":"73d45c382ff1fc33","repo":"github/copilot-sdk","slug":"failed-to-deserialize-permission-request","errorCode":null,"errorMessage":"Failed to deserialize permission request","messagePattern":"Failed to deserialize permission request","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Session.cs","lineNumber":639,"sourceCode":"        _mcpAuthHandler = handler;\n    }\n\n    /// <summary>\n    /// Handles a permission request from the Copilot CLI.\n    /// </summary>\n    /// <param name=\"permissionRequestData\">The permission request data from the CLI.</param>\n    /// <returns>A task that resolves with the permission decision.</returns>\n    internal async Task<PermissionDecision> HandlePermissionRequestAsync(JsonElement permissionRequestData)\n    {\n        var handler = _permissionHandler;\n\n        if (handler == null)\n        {\n            return PermissionDecision.UserNotAvailable();\n        }\n\n        var request = JsonSerializer.Deserialize(permissionRequestData.GetRawText(), SessionEventsJsonContext.Default.PermissionRequest)\n            ?? throw new InvalidOperationException(\"Failed to deserialize permission request\");\n\n        var invocation = new PermissionInvocation\n        {\n            SessionId = SessionId,\n            ManagedSettingsEnabled = _managedSettingsEnabled\n        };\n\n        var permissionTimestamp = Stopwatch.GetTimestamp();\n        var result = await handler(request, invocation);\n        LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,\n            \"CopilotSession.HandlePermissionRequestAsync dispatch. Elapsed={Elapsed}, SessionId={SessionId}\",\n            permissionTimestamp,\n            SessionId);\n        return result;\n    }\n\n    /// <summary>\n    /// Handles broadcast request events by executing local handlers and responding via RPC.","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/Session.cs#L621-L657","documentation":"HandlePermissionRequestAsync receives permission-request payload data from the host and deserializes it into a PermissionRequest via SessionEventsJsonContext. If the JSON cannot be deserialized (shape mismatch, missing required fields) the result is null, which the code treats as a hard invariant failure and throws.","triggerScenarios":"The host sends a permission request (e.g. for a tool call) whose `permissionRequestData` JSON does not match the PermissionRequest schema — wrong field names, wrong types, or an empty payload.","commonSituations":"Version mismatch between host (Copilot CLI/extension) and this SDK causing schema drift; a custom host emitting non-conforming permission payloads; corrupted or truncated JSON-RPC params.","solutions":["Upgrade the host/CLI and the SDK to matching versions so the PermissionRequest schema lines up.","Log permissionRequestData.GetRawText() to inspect the offending payload and identify the schema mismatch.","Catch InvalidOperationException in the permission-request event handler and fall back to PermissionDecision.UserNotAvailable().","If you implement a host, validate permission payloads against the SDK's PermissionRequest contract."],"exampleFix":"// before\ntry { OnPermissionRequest += async e => await DecideAsync(e); }\n\n// after\ntry { var req = e.Request; }\ncatch (InvalidOperationException ex) { Log(ex, e.RawData); return PermissionDecision.UserNotAvailable(); }","handlingStrategy":"try-catch","validationCode":"if (permissionRequestData.ValueKind != JsonValueKind.Object)\n    return PermissionDecision.UserNotAvailable();","typeGuard":"static bool IsDeserializable(JsonElement e) =>\n    e.ValueKind == JsonValueKind.Object && e.TryGetProperty(\"toolCall\", out _);","tryCatchPattern":"try { var request = JsonSerializer.Deserialize(raw, SessionEventsJsonContext.Default.PermissionRequest); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Failed to deserialize permission request\")\n{ Log(raw); return PermissionDecision.UserNotAvailable(); }","preventionTips":["Keep host/CLI and SDK versions in sync","Log raw permission payloads when debugging schema drift","Always provide a fallback decision for undecodable requests"],"tags":["deserialization","json","schema-mismatch","dotnet"],"backgroundTag":"json-unmarshal-failed","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"}