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
- Change the permission handler to always return a concrete decision (approve or deny) instead of NO_RESULT when on v2
- Map 'dismissed/no answer' UI outcomes to an explicit deny before returning the result
- Log the NO_RESULT case and fall back to a deny response so the server always receives exactly one answer
- 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
- Never return NO_RESULT in handlers registered for protocol v2
- Map dismissed/abstained UI outcomes to explicit deny
- Audit handler return kinds when upgrading server protocol version
- Attach exceptionally() to handler futures so callback throws are logged
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
- Unknown ToolDefer value: + value
- session.create response did not include a sessionId.
- workingDirectory is not supported with…
- env is not supported with RuntimeConnection.forInProcess()…
- No session found for sessionId
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)