{"record":{"id":"5a1bf16d4a057a60","repo":"apache/iceberg","slug":"invalid-null-response-body-for-request-expected","errorCode":null,"errorMessage":"Invalid (null) response body for request (expected %s): method=%s, path=%s, status=%d","messagePattern":"Invalid \\(null\\) response body for request \\(expected (.+?)\\): method=(.+?), path=(.+?), status=(.+?)","errorType":"exception","errorClass":"RESTException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/rest/HTTPClient.java","lineNumber":369,"sourceCode":"        // 304-NOT_MODIFIED is used for freshness-aware loading and requires an ETag sent to the\n        // server via IF_NONE_MATCH header in the request. If no ETag was sent, we shouldn't\n        // receive a 304.\n        throw new RESTException(\n            \"Invalid (NOT_MODIFIED) response for request: method=%s, path=%s\",\n            request.method(), request.path());\n      }\n\n      return null;\n    }\n\n    if (!isSuccessful(response)) {\n      // The provided error handler is expected to throw, but a RESTException is thrown if not.\n      String responseBody = extractResponseBodyAsString(response);\n      throwFailure(response, responseBody, errorHandler);\n    }\n\n    if (response.getEntity() == null) {\n      throw new RESTException(\n          \"Invalid (null) response body for request (expected %s): method=%s, path=%s, status=%d\",\n          responseType.getSimpleName(), request.method(), request.path(), response.getCode());\n    }\n\n    ObjectReader reader = objectReaderCache.computeIfAbsent(responseType, mapper::readerFor);\n    if (parserContext != null && !parserContext.isEmpty()) {\n      reader = reader.with(parserContext.toInjectableValues());\n    }\n    return reader.readValue(response.getEntity().getContent());\n  }\n\n  private <T extends RESTResponse> boolean emptyBody(\n      ClassicHttpResponse response, Class<T> responseType) {\n    return response.getCode() == HttpStatus.SC_NO_CONTENT\n        || response.getCode() == HttpStatus.SC_NOT_MODIFIED\n        || (responseType == null && isSuccessful(response));\n  }\n","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/rest/HTTPClient.java#L351-L387","documentation":"handleResponse expects a JSON body for the given responseType after error handling did not throw. If the response has no entity at all (null entity) while a non-empty-body type like LoadTableResponse was expected, the client throws RESTException. It indicates the server responded successfully (or with a non-error status) but without the promised payload.","triggerScenarios":"The server returns a success status (e.g. 200/201) with no response entity for an endpoint the client expects to deserialize into responseType (like a table or namespace metadata response), and emptyBody() does not consider this response empty.","commonSituations":"Misbehaving or partially implemented catalog server; wrong endpoint routed (e.g. loadTable hit a route that only acknowledges); server stripped the body on redirect/replay; custom catalog implementation forgot to serialize the response.","solutions":["Verify with curl that the endpoint actually returns a JSON body for the same request.","Fix the server/route so it returns the expected response type serialized as JSON.","Check for redirect/middleware/proxy configurations that may strip response bodies.","Confirm the client is pointing at the right endpoint (path and method) for the operation."],"exampleFix":"// before: server returns 200 with no body\nreturn Response.ok().build();\n// after: always serialize the expected response\nreturn Response.ok(LoadTableResponse.builder()\n    .withTableMetadata(metadata)\n    .build()).build();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  LoadTableResponse resp = client.post(path, body, LoadTableResponse.class, headers);\n} catch (RESTException e) {\n  if (e.getMessage().contains(\"null) response body\")) {\n    // server returned success without a payload — inspect endpoint/server implementation\n  }\n  throw e;\n}","preventionTips":["Verify server endpoints serialize the declared response type.","Test endpoints with curl to confirm bodies are present.","Watch for middleware or redirect layers that drop response bodies."],"tags":["http","rest-catalog","empty-body","serialization"],"backgroundTag":"empty-response-body","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"}