prestodb/presto · error · PageTransportErrorException
Expected %s response from server but got %s
Error message
Expected %s response from server but got %s
What it means
PrestoSparkHttpTaskClient validates every HTTP response it downloads pages from: the response must declare Content-Type application/vnd.presto.pages (PRESTO_PAGES_TYPE). If the header is absent or a different media type is returned (e.g. an HTML error page or JSON error), it wraps it in a PageTransportErrorException so the caller treats the endpoint as speaking the wrong protocol rather than returning bad data.
Source
Thrown at presto-spark-base/src/main/java/com/facebook/presto/spark/execution/http/PrestoSparkHttpTaskClient.java:768
catch (RuntimeException | IOException e) {
// Ignored. Just return whatever message we were able to decode
}
throw new PageTransportErrorException(
HostAddress.fromUri(request.url().uri()),
format("Expected response code to be 200, but was %s:%n%s",
response.code(),
body.toString()));
}
// invalid content type can happen when an error page is returned, but is unlikely given the above 200
String contentType = response.header(CONTENT_TYPE);
if (contentType == null) {
throw new PageTransportErrorException(
HostAddress.fromUri(request.url().uri()),
format("%s header is not set: %s", CONTENT_TYPE, response));
}
if (!mediaTypeMatches(contentType, PRESTO_PAGES_TYPE)) {
throw new PageTransportErrorException(
HostAddress.fromUri(request.url().uri()),
format("Expected %s response from server but got %s", PRESTO_PAGES_TYPE, contentType));
}
String taskInstanceId = getTaskInstanceId(request, response);
long token = getToken(request, response);
long nextToken = getNextToken(request, response);
boolean complete = getComplete(request, response);
ResponseBody responseBody = response.body();
if (responseBody == null) {
throw new PageTransportErrorException(
HostAddress.fromUri(request.url().uri()),
"Response body is null");
}
SliceInput input = new InputStreamSliceInput(responseBody.byteStream());
List<SerializedPage> pages = ImmutableList.copyOf(readSerializedPages(input));View on GitHub (pinned to 55bb57d202)
Solutions
- Check what the remote actually returned: log/inspect the %s value in the message to see the unexpected content type.
- Verify the target server is a genuine Presto native worker on the expected port, not a proxy or another service.
- Ensure client and server Presto versions match (same pages serialization protocol).
- If a proxy is in the path, bypass it or configure it to pass the response through unchanged (no content-type rewriting, no HTML error interstitials).
- Retry the request; transient worker failures can momentarily return error bodies instead of pages.
Defensive patterns
Strategy: validation
Validate before calling
// before reading pages, check the declared content type
String contentType = response.header("Content-Type");
if (contentType == null || !contentType.contains("application/vnd.presto.pages")) {
throw new IllegalStateException("Non-pages response from " + request.url() + ": " + contentType);
} Type guard
// narrowing guard for a valid pages response
boolean isPagesResponse(Response r) {
String ct = r.header("Content-Type");
return ct != null && ct.trim().startsWith("application/vnd.presto.pages");
} Try / catch
try {
PagesBaseResponse resp = client.getPagesRequest(...);
} catch (PageTransportErrorException e) {
if (e.getMessage() != null && e.getMessage().contains("Expected")) {
// wrong content type: re-discover a healthy worker and retry
}
} Prevention
- Keep proxies/service mesh from rewriting or inspecting worker response bodies.
- Pin client and worker to matching Presto versions.
- Health-check the worker port before issuing pages requests.
- Retry transient failures before failing the task.
When it happens
Trigger: Calling the pages-acquire endpoint (getPagesRequest) and the server replies 200 OK but with a Content-Type other than application/vnd.presto.pages — e.g. an error page from a proxy, a JSON-encoded failure from the native worker, or a custom serializer writing the wrong MIME type.
Common situations: A reverse proxy or load balancer intercepts the request and returns an HTML 4xx/5xx page with text/html; a Presto version mismatch where the Spark-side worker returns pages encoded as JSON instead of the Presto pages media type; a misconfigured native worker binary that does not use Smile/pages serialization.
Related errors
- %s header is not set: %s
- No Content-Type set in response from remote Presto server
- Bad Content-Type from remote Presto server:${contentType}
- shuffleWriteInfo and broadcastBasePath can not be specified
- Error reading response from server
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/99690621ad844f28.
Report an issue: GitHub.