apple/pkl · error · ProtocolException

Unexpected incoming one-way message: ${msg}

Error message

Unexpected incoming one-way message: ${msg}

What it means

runTransport wires the reader's message transport with a handler for unsolicited one-way messages. Since the external reader protocol does not permit the reader to send one-way messages to the host, any such message is a protocol violation and throws ProtocolException, which is wrapped into a RuntimeException that kills the rxThread.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/externalreader/ExternalReaderProcessImpl.java:146

              () -> this.runTransport(myTransport),
              "ExternalReaderProcessImpl rxThread for " + spec);
      rxThread.setDaemon(true);
      rxThread.start();

      return transport;
    }
  }

  /**
   * Runs the underlying message transport so it can receive responses from the child process.
   *
   * <p>Blocks until the underlying transport is closed.
   */
  private void runTransport(MessageTransport transport) {
    try {
      transport.start(
          (msg) -> {
            throw new ProtocolException("Unexpected incoming one-way message: " + msg);
          },
          (msg) -> {
            throw new ProtocolException("Unexpected incoming request message: " + msg);
          });
    } catch (ProtocolException | IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public void close() {
    synchronized (lock) {
      if (closed) return;
      closed = true;

      try {
        if (transport != null && process != null && process.isAlive()) {
          transport.send(new CloseExternalProcess());

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Upgrade the external reader (and pkl-core) so both sides implement the same protocol version
  2. Inspect the received message content (in msg) to identify the protocol deviation
  3. Fix or replace the non-conforming reader implementation
  4. Capture a wire-level log of the transport to diagnose framing desync
Defensive patterns

Strategy: try-catch

Try / catch

try {
  reader.use { ... } // rx thread failures surface as RuntimeException
} catch (RuntimeException e) {
  if (e.getCause() instanceof ProtocolException pe && pe.getMessage().startsWith("Unexpected incoming one-way message")) {
    // protocol mismatch: align reader and pkl-core versions
  }
}

Prevention

When it happens

Trigger: The external reader sends an unexpected one-way message (wrong protocol version, buggy reader implementation, corrupted/framed stream desync causing garbage to be interpreted as a one-way message).

Common situations: Mismatched host/reader protocol versions, a third-party reader implementation deviating from the protocol, stream corruption after a partial write.

Related errors


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