{"record":{"id":"ecdf09b92d0076fd","repo":"apache/pulsar","slug":"bookie-group-parameters-is-missing","errorCode":null,"errorMessage":"Bookie 'group' parameters is missing","messagePattern":"Bookie 'group' parameters is missing","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Bookies.java","lineNumber":185,"sourceCode":"    @POST\n    @Path(\"/racks-info/{bookie}\")\n    @Operation(summary = \"Updates the rack placement information for a specific bookie in the cluster (note.\"\n            + \" bookie address format:`address:port`)\")\n    @ApiResponses(value = {\n            @ApiResponse(responseCode = \"204\", description = \"Operation successful\"),\n            @ApiResponse(responseCode = \"403\", description = \"Don't have admin permission\")}\n    )\n    public void updateBookieRackInfo(@Suspended final AsyncResponse asyncResponse,\n                                     @Parameter(description = \"The bookie address\", required = true)\n                                     @PathParam(\"bookie\") String bookieAddress,\n                                     @Parameter(description = \"The group\", required = true)\n                                     @QueryParam(\"group\") String group,\n                                     @RequestBody(description = \"The bookie info\", required = true)\n                                     BookieInfo bookieInfo) throws Exception {\n        validateSuperUserAccess();\n\n        if (group == null) {\n            throw new RestException(Status.PRECONDITION_FAILED, \"Bookie 'group' parameters is missing\");\n        }\n\n        // validate rack name\n        int separatorCnt = StringUtils.countMatches(\n            StringUtils.strip(bookieInfo.getRack(), PATH_SEPARATOR), PATH_SEPARATOR);\n        boolean isRackEnabled = pulsar().getConfiguration().isBookkeeperClientRackawarePolicyEnabled();\n        boolean isRegionEnabled = pulsar().getConfiguration().isBookkeeperClientRegionawarePolicyEnabled();\n        if (isRackEnabled && ((isRegionEnabled && separatorCnt != 1) || (!isRegionEnabled && separatorCnt != 0))) {\n            asyncResponse.resume(new RestException(Status.PRECONDITION_FAILED, \"Bookie 'rack' parameter is invalid, \"\n                + \"When `RackawareEnsemblePlacementPolicy` is enabled, the rack name is not allowed to contain \"\n                + \"slash (`/`) except for the beginning and end of the rack name string. \"\n                + \"When `RegionawareEnsemblePlacementPolicy` is enabled, the rack name can only contain \"\n                + \"one slash (`/`) except for the beginning and end of the rack name string.\"));\n            return;\n        }\n\n        getPulsarResources().getBookieResources()\n                .update(optionalBookiesRackConfiguration -> {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Bookies.java#L167-L203","documentation":"Thrown by the Bookies admin resource when updating a bookie's rack/group placement info (updateBookieRackInfo). The 'group' query parameter is mandatory — the bookie's placement group is part of the rack-aware policy data stored in the metadata service. A null group cannot be persisted, so the request is rejected up front with HTTP 412 PRECONDITION_FAILED.","triggerScenarios":"POST to /admin/v2/bookies/rackInfo/{bookie} (updateBookieRackInfo) omitting the required 'group' query parameter while supplying a JSON body with the BookieInfo (rack), e.g. curl -X POST .../rackInfo/my-bookie:3181?group= missing entirely.","commonSituations":"Copy-pasted curl commands where ?group= was dropped; automation or UI built against an older API version that did not require group; mixing up 'group' with the rack field in the body; scripts written for the bookie rack update docs of a different Pulsar release.","solutions":["Add the 'group' query parameter to the request, e.g. POST /admin/v2/bookies/rackInfo/{bookie}?group={group} with the BookieInfo JSON body.","In automation, validate that group is non-null before issuing the request and fail fast with a clear message.","Verify the rack name in the body also passes validation (no leading/trailing path separators) to avoid the next rejection."],"exampleFix":"// before\ncurl -X POST 'http://broker:8080/admin/v2/bookies/rackInfo/bk1:3181' \\\n  -H 'Content-Type: application/json' -d '{\"rack\": \"/dc1/rack1\"}'\n\n// after\ncurl -X POST 'http://broker:8080/admin/v2/bookies/rackInfo/bk1:3181?group=rg1' \\\n  -H 'Content-Type: application/json' -d '{\"rack\": \"/dc1/rack1\"}'","handlingStrategy":"validation","validationCode":"if (group == null || group.isEmpty()) {\n    throw new IllegalArgumentException(\"'group' query parameter is required for bookie rack update\");\n}\nadmin.bookies().updateBookieRackInfo(bookie, group, new BookieInfo(rack));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include ?group= in bookie rack-info requests; build URLs from a helper that requires it.","Validate rack strings contain no leading/trailing '/' before sending.","Pin automation to the Pulsar API version whose required parameters you tested."],"tags":["pulsar","admin-api","rest-exception","missing-parameter","bookkeeper"],"backgroundTag":"missing-required-parameter","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}