apple/pkl · error · ProtocolException

unknownRequestId

unknownRequestId

Error message

unknownRequestId

What it means

When a Response message arrives, accept() looks up its requestId in the responseHandlers map and removes it. If no handler is registered for that requestId, a ProtocolException with code unknownRequestId is thrown, since the library cannot route the response to any pending request.

Solutions

  1. Check for duplicate or late responses from the peer and drop responses for unknown ids before calling accept()
  2. Verify the external reader generates unique, monotonic requestIds matching those sent
  3. Avoid cancelling/removing handlers while responses may still be in flight, or handle unknown ids gracefully
  4. Restart the whole transport session cleanly instead of reusing stale handler state

Example fix

// before
transport.accept(response); // throws unknownRequestId
// after
if (transport.hasPendingRequest(response.requestId())) {
  transport.accept(response);
} else {
  LOG.warn("Ignoring stale response for request " + response.requestId());
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (msg instanceof Message.Response r && !pendingRequests.containsKey(r.requestId())) { LOG.warn("dropping stale response " + r.requestId()); return; }

Type guard

boolean isKnownResponse(Message m, Map<Long, ResponseHandler> pending) { return m instanceof Message.Response r && pending.containsKey(r.requestId()); }

Try / catch

try { transport.accept(msg); } catch (ProtocolException e) { if ("unknownRequestId".equals(((ProtocolException) e).getErrorCode())) { LOG.warn("stale/duplicate response ignored"); } else { throw e; } }

Prevention

When it happens

Trigger: A Response arrives whose requestId was never registered, was already completed/removed (duplicate response), or whose handler map was cleared (e.g. after transport close/restart).

Common situations: Duplicate responses from a misbehaving external reader; requests cancelled/timed out locally and removed from the map just before the response arrives; requestId collisions after reusing or restarting a transport; version-mismatched peers generating wrong ids.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/beea45f7aa94f43c. Report an issue: GitHub.

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/messaging/MessageTransports.java:163

      logger.log(formatter.format(args));
    }

    protected abstract void doStart() throws ProtocolException, IOException;

    protected abstract void doClose();

    protected abstract void doSend(Message message) throws ProtocolException, IOException;

    protected void accept(Message message) throws ProtocolException {
      log("Received message: {0}", message);
      if (message instanceof Message.OneWay msg) {
        oneWayHandler.handleOneWay(msg);
      } else if (message instanceof Message.Request msg) {
        requestHandler.handleRequest(msg);
      } else if (message instanceof Message.Response msg) {
        var handler = responseHandlers.remove(msg.requestId());
        if (handler == null) {
          throw new ProtocolException(
              ErrorMessages.create(
                  "unknownRequestId", message.getClass().getSimpleName(), msg.requestId()));
        }
        handler.handleResponse(msg);
      }
    }

    @Override
    public final void start(OneWayHandler oneWayHandler, RequestHandler requestHandler)
        throws ProtocolException, IOException {
      log("Starting transport: {0}", this);
      this.oneWayHandler = oneWayHandler;
      this.requestHandler = requestHandler;
      doStart();
    }

    @Override
    public final void close() {

View on GitHub (pinned to f3efcbfc9b)