{"record":{"id":"f1565647b92fe401","repo":"apache/pulsar","slug":"couldn-t-find-ledgerid-in-path","errorCode":null,"errorMessage":"Couldn't find ledgerid in path","messagePattern":"Couldn't find ledgerid in path","errorType":"exception","errorClass":"NumberFormatException","httpStatus":null,"severity":"error","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java","lineNumber":221,"sourceCode":"                            || layout.getVersion() != LAYOUT_VERSION) {\n                        throw new ReplicationException.CompatibilityException(\n                                \"Incompatible layout found (\" + LAYOUT + \":\" + LAYOUT_VERSION + \")\");\n                    }\n                } catch (RuntimeException pe) {\n                    throw new ReplicationException.CompatibilityException(\n                            \"Invalid data found\", pe);\n                }\n                break;\n            }\n        }\n    }\n\n    private long getLedgerId(String path) throws NumberFormatException {\n        Matcher m = ID_EXTRACTION_PATTERN.matcher(path);\n        if (m.find()) {\n            return Long.parseLong(m.group(1));\n        } else {\n            throw new NumberFormatException(\"Couldn't find ledgerid in path\");\n        }\n    }\n\n    private static String getParentPath(String base, long ledgerId) {\n        String subdir1 = String.format(\"%04x\", ledgerId >> 48 & 0xffff);\n        String subdir2 = String.format(\"%04x\", ledgerId >> 32 & 0xffff);\n        String subdir3 = String.format(\"%04x\", ledgerId >> 16 & 0xffff);\n        String subdir4 = String.format(\"%04x\", ledgerId & 0xffff);\n\n        return String.format(\"%s/%s/%s/%s/%s\",\n                base, subdir1, subdir2, subdir3, subdir4);\n    }\n\n    public static String getUrLedgerPath(String base, long ledgerId) {\n        return String.format(\"%s/urL%010d\", getParentPath(base, ledgerId), ledgerId);\n    }\n\n    public static String getUrLedgerLockPath(String base, long ledgerId) {","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java#L203-L239","documentation":"getLedgerId extracts the numeric ledger id from an underreplication znode path using ID_EXTRACTION_PATTERN. If the regex finds no match (the path doesn't have the expected .../ledgers/region/xx/xx/ledgerId shape), it throws NumberFormatException with this message.","triggerScenarios":"Calling ledgerId/getLedgerId with a path that doesn't conform to the underreplication hierarchy — special znodes (locks, layout, management nodes) or arbitrary paths passed into the underreplication manager's path-parsing APIs.","commonSituations":"Iterating all children of the underreplication root without filtering special znodes; custom tooling constructing paths with wrong format; path changes between Pulsar versions breaking hand-written parsers.","solutions":["Filter out special znodes (AbstractZkLedgerManager.isSpecialZnode or equivalent checks) before parsing paths.","Verify the path matches the expected hierarchical pattern <base>/region/dd/dd/<ledgerId> produced by getParentPath.","Fix the caller to only pass paths obtained from getLedgerList/underreplication hierarchy rather than arbitrary znode paths.","If building paths yourself, use getParentPath-style formatting (String.format(\"%04x\", ...)) rather than string concatenation."],"exampleFix":"// before\nlong id = urManager.ledgerId(anyChildPath);\n// after\nif (AbstractZkLedgerManager.isSpecialZnode(anyChildPath)) {\n    return; // skip layout/lock nodes\n}\nlong id = urManager.ledgerId(anyChildPath);","handlingStrategy":"type-guard","validationCode":"private static final Pattern LEDGER_PATH = Pattern.compile(\".*/(\\\\d+)$\");\nboolean isLedgerPath(String p) { return LEDGER_PATH.matcher(p).matches(); }","typeGuard":"boolean isParseableLedgerPath(String path) {\n    return path != null && ID_EXTRACTION_PATTERN.matcher(path).find();\n}","tryCatchPattern":"try {\n    long id = urManager.ledgerId(path);\n} catch (NumberFormatException e) {\n    log.debug(\"Skipping non-ledger znode path {}\", path);\n}","preventionTips":["Skip special znodes before parsing paths from the underreplication hierarchy.","Only feed paths produced by the underreplication manager's own path builders into ledgerId().","Use isSpecialZnode-style checks when iterating children of the underreplication root."],"tags":["bookkeeper","underreplication","path-parsing","numberformatexception"],"backgroundTag":"invalid-ledger-path","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"}