apple/pkl · error · IOException

external read failure:

Error message

external read failure: 

What it means

This IOException is thrown by MessageTransports.resolveFuture when a transport request future completes exceptionally. If the underlying cause is an IOException it is rethrown as-is; otherwise the original message is wrapped as "external read failure: <message>" with the original cause attached. It signals that the external process/transport backing an evaluation (e.g. an external reader) failed while reading a response.

Source

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

  }

  /** Creates "client" and "server" transports that are directly connected to each other. */
  public static Pair<MessageTransport, MessageTransport> direct(Logger logger) {
    var transport1 = new DirectMessageTransport(logger);
    var transport2 = new DirectMessageTransport(logger);
    transport1.setOther(transport2);
    transport2.setOther(transport1);
    return Pair.of(transport1, transport2);
  }

  public static <T extends @Nullable Object> T resolveFuture(Future<T> future) throws IOException {
    try {
      return future.get();
    } catch (ExecutionException | InterruptedException e) {
      if (e.getCause() instanceof IOException ioExc) {
        throw ioExc;
      } else {
        throw new IOException("external read failure: " + e.getMessage(), e.getCause());
      }
    }
  }

  protected static class EncodingMessageTransport extends AbstractMessageTransport {

    private final MessageDecoder decoder;
    private final MessageEncoder encoder;
    private volatile boolean isClosed = false;

    protected EncodingMessageTransport(
        MessageDecoder decoder, MessageEncoder encoder, Logger logger) {
      super(logger);
      this.decoder = decoder;
      this.encoder = encoder;
    }

    @Override

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Inspect the wrapped cause (getCause()) to find the real failure in the external reader process
  2. Verify the external reader process is alive, on the supported protocol version, and not crashing on the requested resource
  3. Retry the evaluation; transient process/IPC failures often resolve on retry
  4. Catch IOException at the evaluation call site and surface the cause chain to the user
  5. Upgrade Pkl / the external reader to matching versions if a protocol mismatch is suspected

Example fix

// before
var result = transport.resolveFuture(future); // throws IOException("external read failure: ...")
// after
try {
  var result = transport.resolveFuture(future);
} catch (IOException e) {
  LOG.error("external reader failed", e.getCause());
  throw new UncheckedIOException("External reader failed: " + e.getCause().getMessage(), e.getCause());
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (future.isCompletedExceptionally()) { future.exceptionally(ex -> { LOG.error("external transport will fail: ", ex); return null; }).join(); }

Type guard

boolean isIoFailure(Throwable t) { Throwable c = t instanceof ExecutionException e ? e.getCause() : t; return c instanceof IOException; }

Try / catch

try { var v = resolveFuture(future); } catch (IOException e) { Throwable cause = e.getCause(); LOG.error("external read failed", cause); throw new UncheckedIOException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new CancellationException(); }

Prevention

When it happens

Trigger: A MessageTransport request future (e.g. from an external reader process handling a module/resource read) completes with an ExecutionException whose cause is not an IOException, and the caller calls resolveFuture which blocks on future.get().

Common situations: External reader processes crashing or timing out mid-request; class-casting or protocol errors inside the transport handler; a dependency of the external reader throwing an unexpected exception type; killed child processes during evaluation.

Related errors


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