apache/iceberg · warning

Unable to parse error response

Error message

Unable to parse error response

What it means

ErrorHandlers' REST error parser converts an HTTP error body into an ErrorResponse via ErrorResponseParser.fromJson. If the body is not valid REST-catalog error JSON (or any parse exception occurs), this warning is logged and a fallback ErrorResponse containing the raw body as the message and the HTTP code is returned, so the original failure is not lost.

Solutions

  1. Check the actual endpoint: verify rest.catalog.io-impl URL points to the REST catalog, not a UI or proxy.
  2. Inspect server/proxy logs for the true error behind the non-JSON body.
  3. Increase client debug logging to see the raw response body included in the fallback ErrorResponse message.
  4. Fix upstream (disable HTML error pages, ensure catalog returns RFC-compliant ErrorResponse JSON).
Defensive patterns

Strategy: fallback

Try / catch

try { tableScan.planFiles(); } catch (RESTException e) { LOG.error("REST error (body may be non-JSON): {}", e.getMessage(), e); }

Prevention

When it happens

Trigger: A REST catalog server returns a non-standard error payload (HTML error page, plain text, proxy 502 body, empty/invalid JSON) and the client calls errorHandler.parseResponse(code, json) while handling the failed response.

Common situations: Reverse proxies/load balancers returning HTML on 502/504, misconfigured catalog endpoints pointing at a web UI, non-Iceberg servers behind the REST URL, chunked/truncated responses.

Understand the failure class

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/720f9b912c62e017. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/rest/ErrorHandlers.java:329

      }

      super.accept(error);
    }
  }

  /**
   * Request error handler that handles the common cases that are included with all responses, such
   * as 400, 500, etc.
   */
  private static class DefaultErrorHandler extends ErrorHandler {
    private static final ErrorHandler INSTANCE = new DefaultErrorHandler();

    @Override
    public ErrorResponse parseResponse(int code, String json) {
      try {
        return ErrorResponseParser.fromJson(json);
      } catch (Exception x) {
        LOG.warn("Unable to parse error response", x);
      }
      return ErrorResponse.builder().responseCode(code).withMessage(json).build();
    }

    @Override
    public void accept(ErrorResponse error) {
      switch (error.code()) {
        case 400:
          if (IllegalArgumentException.class.getSimpleName().equals(error.type())) {
            throw new IllegalArgumentException(error.message());
          }
          throw new BadRequestException("Malformed request: %s", error.message());
        case 401:
          throw new NotAuthorizedException("Not authorized: %s", error.message());
        case 403:
          throw new ForbiddenException("Forbidden: %s", error.message());
        case 405:
        case 406:

View on GitHub (pinned to 86d9c8fc54)