prestodb/presto · error · PrestoException

NATIVEPLANCHECKER_UNKNOWN_CONVERSION_FAILURE

NATIVEPLANCHECKER_UNKNOWN_CONVERSION_FAILURE

Error message

Error response without failure from native plan checker with code: {statusCode}

What it means

When the plan checker returns a non-200 response, NativePlanChecker.processResponseFailure expects the body to decode into a PlanConversionResponse containing failure info. If the body is null or empty, there is nothing to convert, so it throws NATIVEPLANCHECKER_UNKNOWN_CONVERSION_FAILURE with the HTTP status code — the real failure reason is unknown.

Source

Thrown at presto-native-sidecar-plugin/src/main/java/com/facebook/presto/sidecar/nativechecker/NativePlanChecker.java:231

                .setHeader(CONTENT_TYPE, JSON_UTF_8.toString())
                .setBodyGenerator(createStaticBodyGenerator(requestBodyJson, UTF_8))
                .build();
    }

    private URI getSidecarLocation()
    {
        Node sidecarNode = nodeManager.getSidecarNode();
        return HttpUriBuilder
                .uriBuilderFrom(sidecarNode.getHttpUri())
                .appendPath(PLAN_CONVERSION_ENDPOINT)
                .build();
    }

    private NativeSidecarFailureInfo processResponseFailure(StringResponse response)
    {
        String responseBody = response.getBody();
        if (responseBody == null || responseBody.isEmpty()) {
            throw new PrestoException(NATIVEPLANCHECKER_UNKNOWN_CONVERSION_FAILURE, "Error response without failure from native plan checker with code: " + response.getStatusCode());
        }

        PlanConversionResponse planConversionResponse = PLAN_CONVERSION_RESPONSE_JSON_CODEC.fromJson(responseBody);
        if (planConversionResponse.getFailures().isEmpty()) {
            throw new PrestoException(NATIVEPLANCHECKER_UNKNOWN_CONVERSION_FAILURE, "Error response without failure from native plan checker with code: " + response.getStatusCode());
        }

        return planConversionResponse.getFailures().get(0);
    }

    private static class CheckInternalVisitor
            extends PlanVisitor<Boolean, Void>
    {
        @Override
        public Boolean visitTableScan(TableScanNode tableScan, Void context)
        {
            TableHandle handle = tableScan.getTable();
            return ConnectorId.isInternalSystemConnector(handle.getConnectorId());

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Check the HTTP status code in the message and the sidecar/proxy logs for that request.
  2. If a proxy returns empty 502/504, fix connectivity/timeouts between coordinator and sidecar.
  3. Check sidecar container logs for a crash (OOM) during plan conversion.
  4. Retry the query once sidecar is healthy; ensure sidecar returns structured failure JSON on errors.
Defensive patterns

Strategy: retry

Validate before calling

// require structured errors from the checker service
assertSidecarReturnsJsonErrors(); // verify sidecar never returns bare/empty error bodies

Type guard

boolean hasFailureBody(StringResponse r) { return r.getBody() != null && !r.getBody().isEmpty(); }

Try / catch

try { validateFragment(fragment); }
catch (PrestoException e) {
    if ("NATIVEPLANCHECKER_UNKNOWN_CONVERSION_FAILURE".equals(e.getErrorCode().getName())) {
        log.warn("Empty checker error body; checking sidecar/proxy health then retrying");
        if (sidecarHealthy()) retryOnce(); else failFast(e);
    } else throw e;
}

Prevention

When it happens

Trigger: validateFragment -> runValidation gets a non-200 response whose body is null or empty; processResponseFailure hits the first guard.

Common situations: Sidecar crashing mid-request (empty 500 body); proxy/load balancer intercepting and returning bare status codes (502/504 with empty body); request timeout at the gateway.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/d541dd6b484d533a. Report an issue: GitHub.