{"record":{"id":"9dfcaedb9f07aff5","repo":"apache/iceberg","slug":"unhandled-error-s","errorCode":null,"errorMessage":"Unhandled error: %s","messagePattern":"Unhandled error: (.+?)","errorType":"exception","errorClass":"RESTException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/rest/HTTPClient.java","lineNumber":245,"sourceCode":"        // without any bugs in the server implementation. So we ignore this exception and build an\n        // error\n        // response for the user.\n        //\n        // For example, the connection could time out before every reaching the server, in which\n        // case we'll\n        // likely get a 5xx with the load balancers default 5xx response.\n        LOG.error(\"Failed to parse an error response. Will create one instead.\", e);\n      }\n    }\n\n    if (errorResponse == null) {\n      errorResponse = buildDefaultErrorResponse(response);\n    }\n\n    errorHandler.accept(errorResponse);\n\n    // Throw an exception in case the provided error handler does not throw.\n    throw new RESTException(\"Unhandled error: %s\", errorResponse);\n  }\n\n  @Override\n  protected HTTPRequest buildRequest(\n      HTTPMethod method,\n      String path,\n      Map<String, String> queryParams,\n      Map<String, String> headers,\n      Object body) {\n\n    ImmutableHTTPRequest.Builder builder =\n        ImmutableHTTPRequest.builder()\n            .baseUri(baseUri)\n            .mapper(mapper)\n            .method(method)\n            .path(path)\n            .body(body)\n            .queryParameters(queryParams == null ? Map.of() : queryParams);","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/rest/HTTPClient.java#L227-L263","documentation":"After receiving a failed HTTP response, HTTPClient passes the built ErrorResponse to the configured error handler; if that handler returns without throwing (handlers are expected to always throw for errors), this fallback RESTException is thrown so the failure is never silently swallowed. The message stringifies the ErrorResponse (status, type, message).","triggerScenarios":"A non-success HTTP response where the custom or default error handler's accept() completed without throwing — e.g. a custom handler that only handles certain codes (like 401 token refresh handlers that swallow or return) and an unhandled error status arrives.","commonSituations":"Using a partial custom ErrorHandler that omits a case for the status the server returned, or a retrying auth handler that delegates only for 401 and lets other statuses fall through to this line.","solutions":["Read the ErrorResponse in the message to learn the actual HTTP status and server error","Extend your custom ErrorHandler to throw an appropriate exception for every unhandled status","Ensure your handler always terminates with a throw for any non-success response","Fall back to the default handler (ErrorHandlers.defaultErrorHandler()) for statuses you don't handle"],"exampleFix":"// before\nErrorHandler handler = error -> {\n  if (error.code() == 401) throw new NotAuthorizedException(\"reauth\");\n  // other codes: falls through -> 'Unhandled error'\n};\n// after\nErrorHandler handler = error -> {\n  if (error.code() == 401) throw new NotAuthorizedException(\"reauth\");\n  defaultHandler.accept(error); // always throws for any other error\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  client.execute(request, customHandler, responseType);\n} catch (RESTException e) {\n  // 'Unhandled error' means the custom handler didn't throw — inspect e.getMessage()\n  parseErrorResponseAndHandle(e.getMessage());\n}","preventionTips":["Custom ErrorHandlers must throw for every non-success response","Delegate unhandled statuses to the default handler","Unit-test custom handlers against all error statuses your server can return"],"tags":["rest","http-client","error-handler","fallback"],"backgroundTag":"http-error-response","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}