{"record":{"id":"2f7c802c6edee42b","repo":"apache/pulsar","slug":"messageid-is-null","errorCode":null,"errorMessage":"messageId is null","messagePattern":"messageId is null","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java","lineNumber":4037,"sourceCode":"            @ApiResponse(responseCode = \"405\", description = \"Operation is not allowed on the persistent topic\"),\n            @ApiResponse(responseCode = \"409\", description = \"Offload already running\"),\n            @ApiResponse(responseCode = \"412\", description = \"Topic name is not valid\"),\n            @ApiResponse(responseCode = \"500\", description = \"Internal server error\"),\n            @ApiResponse(responseCode = \"503\", description = \"Failed to validate global cluster configuration\")})\n    public void triggerOffload(\n            @Suspended final AsyncResponse asyncResponse,\n            @Parameter(description = \"Specify the tenant\", required = true)\n            @PathParam(\"tenant\") String tenant,\n            @Parameter(description = \"Specify the namespace\", required = true)\n            @PathParam(\"namespace\") String namespace,\n            @Parameter(description = \"Specify topic name\", required = true)\n            @PathParam(\"topic\") @Encoded String encodedTopic,\n            @Parameter(description = \"Whether leader broker redirected this call to this broker. For internal use.\")\n            @QueryParam(\"authoritative\") @DefaultValue(\"false\") boolean authoritative,\n                               MessageIdImpl messageId) {\n        try {\n            if (messageId == null) {\n                throw new RestException(Response.Status.BAD_REQUEST, \"messageId is null\");\n            }\n            validateTopicName(tenant, namespace, encodedTopic);\n            internalTriggerOffload(asyncResponse, authoritative, messageId);\n        } catch (WebApplicationException wae) {\n            asyncResponse.resume(wae);\n        } catch (Exception e) {\n            asyncResponse.resume(new RestException(e));\n        }\n    }\n\n    @GET\n    @Path(\"/{tenant}/{namespace}/{topic}/offload\")\n    @Operation(summary = \"Offload a prefix of a topic to long term storage\")\n    @ApiResponses(value = {\n            @ApiResponse(\n                    responseCode = \"200\",\n                    description = \"Offload a prefix of a topic to long term storage\",\n                    content = @Content(schema = @Schema(implementation = OffloadProcessStatus.class))),","sourceCodeStart":4019,"sourceCodeEnd":4055,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/PersistentTopics.java#L4019-L4055","documentation":"The triggerOffload admin endpoint requires a MessageIdImpl request body identifying the ledger/entry to offload. When the body is missing or null the endpoint immediately returns HTTP 400 with 'messageId is null'.","triggerScenarios":"POST /admin/v2/persistent/{tenant}/{namespace}/{topic}/offload with an empty body or JSON that does not deserialize into MessageIdImpl (e.g. wrong field names, non-JSON body).","commonSituations":"curl calls without -d payload; using MessageId instances of another implementation type that fail Jackson deserialization; client libs that serialize MessageId as a string instead of the ledgerId/entryId object.","solutions":["Send a JSON body like {\"ledgerId\":123,\"entryId\":4} (with partitionIndex if applicable)","Use the admin client method admin.topics().triggerOffload(topic, messageId) which serializes correctly","Check the request Content-Type is application/json"],"exampleFix":"// before\ncurl -X POST .../persistent/public/default/t/offload\n// after\ncurl -X POST -H 'Content-Type: application/json' \\\n  -d '{\"ledgerId\":4711,\"entryId\":0}' .../persistent/public/default/t/offload","handlingStrategy":"validation","validationCode":"if (messageId == null) throw new IllegalArgumentException(\"Provide a MessageId (ledgerId/entryId) to offload\");","typeGuard":"boolean isOffloadable(MessageId id) { return id instanceof MessageIdImpl && ((MessageIdImpl) id).getLedgerId() >= 0; }","tryCatchPattern":"try { admin.topics().triggerOffload(topic, messageId); } catch (PulsarAdminException e) { if (e.getStatusCode() == 400) { /* check request body */ } }","preventionTips":["Always send a JSON body with ledgerId/entryId for the offload endpoint","Use the PulsarAdmin client instead of raw curl","Set Content-Type: application/json on manual calls"],"tags":["rest-api","offload","validation"],"backgroundTag":"missing-request-body","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}