{"record":{"id":"7d3f3b5baff92496","repo":"apache/pulsar","slug":"ioexception-7d3f3b","errorCode":null,"errorMessage":"IOException","messagePattern":"IOException","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerIdGenerator.java","lineNumber":275,"sourceCode":"    }\n\n    /**\n     * Checks the existence of the long ledger id gen path. Existence indicates we have switched from the legacy\n     * algorithm to the new method of generating 63-bit ids. If the existence is UNKNOWN, it looks in zk to\n     * find out. If it previously checked in zk, it returns that value. This value changes when we run out\n     * of ids < Integer.MAX_VALUE, and try to create the long ledger id gen path.\n     */\n    public CompletableFuture<Boolean> ledgerIdGenPathPresent() {\n        return store.exists(ledgerIdGenPath);\n    }\n\n    private static long getLedgerIdFromGenPath(String nodeName, String ledgerPrefix) throws IOException {\n        try {\n            String[] parts = nodeName.split(ledgerPrefix);\n            long ledgerId = Long.parseLong(parts[parts.length - 1]);\n            return ledgerId;\n        } catch (NumberFormatException e) {\n            throw new IOException(e);\n        }\n    }\n\n    private static String createLedgerPrefix(String ledgersPath, String idGenZnodeName) {\n        String ledgerIdGenPath = null;\n        if (StringUtils.isBlank(idGenZnodeName)) {\n            ledgerIdGenPath = ledgersPath;\n        } else {\n            ledgerIdGenPath = ledgersPath + \"/\" + idGenZnodeName;\n        }\n\n        return ledgerIdGenPath + \"/\" + \"ID-\";\n    }\n\n    //If the config rootPath when use zk metadata store, it will append rootPath as the prefix of the path.\n    //So when we get the path from the stat, we should truncate the rootPath.\n    private String handleTheDeletePath(String path) {\n        if (store instanceof DualMetadataStore dms) {","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerIdGenerator.java#L257-L293","documentation":"getLedgerIdFromGenPath() parses the ledger id out of the trailing segment of an ephemeral ledger-generation znode name. If the node name does not end in a parseable long after the ledger prefix (NumberFormatException), it is wrapped in an IOException. This indicates a corrupted or foreign znode inside the short-ledger-id generation path.","triggerScenarios":"internalGenerateShortLedgerId()/ledgerId() iterate children of the ledgersRootPath/idGenPath; a child znode whose name lacks the expected '<prefix>' + numeric-id format is passed to getLedgerIdFromGenPath(), producing NumberFormatException -> IOException.","commonSituations":"Manual znode creation or edits in the /ledgers path; leftover or malformed nodes from an aborted BookKeeper version migration; external tools writing non-ledger nodes into the idgen directory.","solutions":["Inspect the znodes under the ledger id-generation path in ZooKeeper and delete/rename malformed nodes that do not match the expected ledger prefix pattern.","Do not create arbitrary znodes inside the ledgers root; only BookKeeper should manage that subtree.","If corruption came from a version migration, restore the metadata from backup or run the appropriate BookKeeper metadata repair tooling.","Upgrade/patch: some BookKeeper versions harden this path; verify your metadata/bookkeeper versions match the supported matrix."],"exampleFix":"// before\nlong ledgerId = ledgerIdGenerator.ledgerId(path); // IOException on malformed znode\n// after\ntry {\n    long ledgerId = ledgerIdGenerator.ledgerId(path);\n} catch (IOException e) {\n    LOG.error(\"Malformed ledger-id znode in generation path: {}\", e.getMessage());\n    // inspect and clean the offending znode in the metadata store\n}","handlingStrategy":"validation","validationCode":"// Validate znode names before they reach the id generator\nboolean isWellFormedLedgerNode(String nodeName, String prefix) {\n    String suffix = nodeName.startsWith(prefix) ? nodeName.substring(prefix.length()) : \"\";\n    return !suffix.isEmpty() && suffix.chars().allMatch(c -> Character.isDigit(c) || c == '-');\n}","typeGuard":"Long tryParseLedgerId(String nodeName, String ledgerPrefix) {\n    try {\n        String[] parts = nodeName.split(ledgerPrefix);\n        return Long.parseLong(parts[parts.length - 1]);\n    } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {\n        return null; // malformed node\n    }\n}","tryCatchPattern":"try {\n    long id = ledgerIdGenerator.ledgerId(genPath);\n} catch (IOException e) {\n    LOG.error(\"Malformed ledger id-gen znode; inspect metadata store path {}\", genPath, e);\n}","preventionTips":["Never create foreign znodes inside the BookKeeper ledgers root","Audit the idgen path after failed migrations or manual interventions","Skip-and-log malformed children rather than aborting the whole id-generation pass","Restore metadata from backup if znode corruption is widespread"],"tags":["zookeeper","metadata-corruption","parsing"],"backgroundTag":"malformed-znode-name","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"}