{"record":{"id":"e22fa4ef7a8a3b53","repo":"apache/pulsar","slug":"the-path-path-doesn-t-look-like-a-valid-path-fo","errorCode":null,"errorMessage":"The path ${path} doesn't look like a valid path for a BookieServiceInfo node","messagePattern":"The path (.+?) doesn't look like a valid path for a BookieServiceInfo node","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/BookieServiceInfoSerde.java","lineNumber":113,"sourceCode":"     * Extract the BookieId\n     * The path should look like /ledgers/available/bookieId\n     * or /ledgers/available/readonly/bookieId.\n     * But the prefix depends on the configuration.\n     * @param path\n     * @return the bookieId\n     */\n    private static String extractBookiedIdFromPath(String path) throws IOException {\n        // https://github.com/apache/bookkeeper/blob/\n        // 034ef8566ad037937a4d58a28f70631175744f53/bookkeeper-server/\n        // src/main/java/org/apache/bookkeeper/discover/ZKRegistrationClient.java#L258\n        if (path == null) {\n            path = \"\";\n        }\n        int last = path.lastIndexOf(\"/\");\n        if (last >= 0) {\n            return path.substring(last + 1);\n        } else {\n            throw new IOException(\"The path \" + path + \" doesn't look like a valid path for a BookieServiceInfo node\");\n        }\n    }\n}\n","sourceCodeStart":95,"sourceCodeEnd":117,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/BookieServiceInfoSerde.java#L95-L117","documentation":"IOException thrown by BookieServiceInfoSerde.extractBookiedIdFromPath when the metadata-store path has no '/' separator, so no bookie id can be extracted as the trailing path segment. The serde expects paths shaped like <bookie-service-info-root>/<bookieId>.","triggerScenarios":"Calling bookieId() (which delegates to extractBookiedIdFromPath) with a path that is empty, a bare name without '/', or a malformed node path read from the metadata store.","commonSituations":"Metadata store containing an unexpected node directly at the root of the bookie-service-info directory; a bug or refactor producing relative paths without the root prefix; empty path after a failed substring operation.","solutions":["Verify the path passed to the serde includes the full bookie-service-info prefix followed by the bookie id","Check the metadata store for stray/malformed nodes under the bookie-service-info root and remove them","Add a pre-check that the path contains '/' before parsing"],"exampleFix":"// before\nString id = serde.bookieId(pathFromStore); // throws if path has no '/'\n// after\nif (pathFromStore == null || !pathFromStore.contains(\"/\")) {\n    LOG.warn(\"Skipping malformed bookie service info path: {}\", pathFromStore);\n    return;\n}\nString id = serde.bookieId(pathFromStore);","handlingStrategy":"validation","validationCode":"if (path == null || !path.contains(\"/\")) {\n    throw new IllegalArgumentException(\"not a BookieServiceInfo path: \" + path);\n}","typeGuard":"static boolean isBookieServiceInfoPath(String path) {\n    return path != null && path.lastIndexOf('/') >= 0\n        && path.lastIndexOf('/') < path.length() - 1;\n}","tryCatchPattern":"try {\n    String id = serde.bookieId(path);\n} catch (IOException e) {\n    LOG.warn(\"Skipping malformed bookie info path: {}\", path);\n}","preventionTips":["Always pass fully-qualified store paths including the service-info root","Audit the metadata store for stray nodes under the bookie-service-info root","Validate paths when reading nodes before handing them to the serde"],"tags":["metadata-store","bookkeeper","path-parsing"],"backgroundTag":"invalid-path-format","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"}