github/copilot-sdk · error · IllegalStateException

Permission handlers cannot return 'no-result' when…

Error message

Permission handlers cannot return 'no-result' when connected to a protocol v2 server.

What it means

This IllegalStateException is raised by RpcHandlerDispatcher.handlePermissionRequest when a registered permission handler resolves a permission request with kind 'no-result' while connected to a protocol v2 server. Protocol v2 requires exactly one response per request, so an abstaining handler would leave the server waiting forever; the dispatcher rejects it. Note the exception is thrown inside a thenAccept callback, so it propagates to the completion handler rather than the caller.

Solutions

  1. Change the permission handler to always return a concrete decision (approve or deny) instead of NO_RESULT when on v2
  2. Map 'dismissed/no answer' UI outcomes to an explicit deny before returning the result
  3. Log the NO_RESULT case and fall back to a deny response so the server always receives exactly one answer
  4. Verify the negotiated protocol version and use v1-compatible abstention only when connected to v1

Example fix

// before
if (userDismissed) {
    return new PermissionRequestResult(PermissionRequestResultKind.NO_RESULT);
}
// after
if (userDismissed) {
    return new PermissionRequestResult(PermissionRequestResultKind.DENY);
}
Defensive patterns

Strategy: validation

Validate before calling

if (PermissionRequestResultKind.NO_RESULT.getValue().equalsIgnoreCase(result.getKind())) {
    result = new PermissionRequestResult(PermissionRequestResultKind.DENY);
}

Try / catch

session.handlePermissionRequest(req)
    .thenAccept(result -> { /* ensure kind != NO_RESULT before dispatch */ })
    .exceptionally(ex -> { LOG.log(Level.SEVERE, "permission handler failed", ex); return null; });

Prevention

When it happens

Trigger: A session.handlePermissionRequest implementation returns a PermissionRequestResult whose getKind() equals the NO_RESULT value, while the dispatcher is serving a v2 protocol server (registerHandlers wired the permission handler for v2).

Common situations: Shared handler code written for protocol v1 (where no-result/abstain was allowed) reused against a v2 server; UI permission prompts that can be dismissed without an answer and map dismissal to NO_RESULT; upgrading the server to v2 without auditing handler return kinds.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at java/sdk/src/main/java/com/github/copilot/RpcHandlerDispatcher.java:298

            try {
                String sessionId = params.get("sessionId").asText();
                JsonNode permissionRequest = params.get("permissionRequest");

                CopilotSession session = sessions.get(sessionId);
                if (session == null) {
                    var result = new PermissionRequestResult()
                            .setKind(PermissionRequestResultKind.DENIED_COULD_NOT_REQUEST_FROM_USER);
                    rpc.sendResponse(requestIdLong, Map.of("result", result));
                    return;
                }

                session.handlePermissionRequest(permissionRequest).thenAccept(result -> {
                    try {
                        if (PermissionRequestResultKind.NO_RESULT.getValue().equalsIgnoreCase(result.getKind())) {
                            // Protocol v2 does not support NO_RESULT — the server
                            // expects exactly one response per request, so abstaining
                            // would leave it hanging.
                            throw new IllegalStateException(
                                    "Permission handlers cannot return 'no-result' when connected to a protocol v2 server.");
                        }
                        rpc.sendResponse(requestIdLong, Map.of("result", result));
                    } catch (IOException e) {
                        LOG.log(Level.SEVERE, "Error sending permission result", e);
                    }
                }).exceptionally(ex -> {
                    try {
                        var result = new PermissionRequestResult()
                                .setKind(PermissionRequestResultKind.DENIED_COULD_NOT_REQUEST_FROM_USER);
                        rpc.sendResponse(requestIdLong, Map.of("result", result));
                    } catch (IOException e) {
                        LOG.log(Level.SEVERE, "Error sending permission denied", e);
                    }
                    return null;
                });
            } catch (Exception e) {
                LOG.log(Level.SEVERE, "Error handling permission request", e);

View on GitHub (pinned to cd8cf15dc3)