{"record":{"id":"3f2d70d6434a46fc","repo":"apple/pkl","slug":"unexpected-incoming-one-way-message-msg","errorCode":null,"errorMessage":"Unexpected incoming one-way message: ${msg}","messagePattern":"Unexpected incoming one-way message: (.+?)","errorType":"exception","errorClass":"ProtocolException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/externalreader/ExternalReaderProcessImpl.java","lineNumber":146,"sourceCode":"              () -> this.runTransport(myTransport),\n              \"ExternalReaderProcessImpl rxThread for \" + spec);\n      rxThread.setDaemon(true);\n      rxThread.start();\n\n      return transport;\n    }\n  }\n\n  /**\n   * Runs the underlying message transport so it can receive responses from the child process.\n   *\n   * <p>Blocks until the underlying transport is closed.\n   */\n  private void runTransport(MessageTransport transport) {\n    try {\n      transport.start(\n          (msg) -> {\n            throw new ProtocolException(\"Unexpected incoming one-way message: \" + msg);\n          },\n          (msg) -> {\n            throw new ProtocolException(\"Unexpected incoming request message: \" + msg);\n          });\n    } catch (ProtocolException | IOException e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  @Override\n  public void close() {\n    synchronized (lock) {\n      if (closed) return;\n      closed = true;\n\n      try {\n        if (transport != null && process != null && process.isAlive()) {\n          transport.send(new CloseExternalProcess());","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/externalreader/ExternalReaderProcessImpl.java#L128-L164","documentation":"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.","triggerScenarios":"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).","commonSituations":"Mismatched host/reader protocol versions, a third-party reader implementation deviating from the protocol, stream corruption after a partial write.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  reader.use { ... } // rx thread failures surface as RuntimeException\n} catch (RuntimeException e) {\n  if (e.getCause() instanceof ProtocolException pe && pe.getMessage().startsWith(\"Unexpected incoming one-way message\")) {\n    // protocol mismatch: align reader and pkl-core versions\n  }\n}","preventionTips":["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"],"tags":["pkl","protocol","reader","ipc"],"backgroundTag":"protocol-violation","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}