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
- Upgrade the external reader (and pkl-core) so both sides implement the same protocol version
- Inspect the received message content (in msg) to identify the protocol deviation
- Fix or replace the non-conforming reader implementation
- 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
- Keep external reader binaries and pkl-core on matching protocol versions
- Only use reader implementations that conform to the documented one-way-message rules
- Log all messages from the reader during development to catch deviations early
- Fail fast in CI by running a smoke evaluation with your reader binary
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
- Unexpected incoming request message: ${msg}
- Unexpected end of input; 0 message bytes
- externalReaderAlreadyTerminated
- Node `%s` of type `%s` does not have a property named `%s`.
- JavaType token must be parameterized.
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/3f2d70d6434a46fc.
Report an issue: GitHub.