{"record":{"id":"70ccc01ef0d085c4","repo":"apache/pulsar","slug":"error-reading-list","errorCode":null,"errorMessage":"Error reading list","messagePattern":"Error reading list","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java","lineNumber":542,"sourceCode":"                            String child = parent + \"/\" + c;\n                            if (c.startsWith(\"urL\")) {\n                                long ledgerId = getLedgerId(child);\n                                UnderreplicatedLedger underreplicatedLedger = getLedgerUnreplicationInfo(ledgerId);\n                                if (underreplicatedLedger != null) {\n                                    List<String> replicaList = underreplicatedLedger.getReplicaList();\n                                    if ((predicate == null) || predicate.test(replicaList)) {\n                                        curBatch.add(underreplicatedLedger);\n                                    }\n                                }\n                            } else {\n                                queue.add(child);\n                            }\n                        }\n                    } catch (InterruptedException ie) {\n                        Thread.currentThread().interrupt();\n                        return false;\n                    } catch (Exception e) {\n                        throw new RuntimeException(\"Error reading list\", e);\n                    }\n                }\n                return curBatch.size() > 0;\n            }\n\n            @Override\n            public UnderreplicatedLedger next() {\n                assert curBatch.size() > 0;\n                return curBatch.remove();\n            }\n        };\n    }\n\n    private long getLedgerToRereplicateFromHierarchy(String parent, long depth)\n            throws ExecutionException, InterruptedException, TimeoutException {\n        if (depth == 4) {\n            List<String> children = new ArrayList<>(store.getChildren(parent)\n                    .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS));","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java#L524-L560","documentation":"Unchecked RuntimeException thrown from the hasNext() of the iterator returned by listLedgersToRereplicate when fetching children or underreplication info from the metadata store fails (any non-interrupt Exception, including ExecutionException/TimeoutException from the blocking .get() call). Because it surfaces lazily while iterating, it escapes Iterator.hasNext()/next() rather than the listLedgersToRereplicate call itself.","triggerScenarios":"Iterating the iterator from listLedgersToRereplicate(predicate) when: store.getChildren(parent).get() times out (BLOCKING_CALL_TIMEOUT exceeded) or fails; or getLedgerUnreplicationInfo(ledgerId) throws for a child urL znode; or the parent hierarchy path is missing/corrupt in the metadata store.","commonSituations":"ZooKeeper connection loss or session expiry mid-iteration over a large underreplicated-ledger tree; hierarchy cleanup races deleting a parent node between listing and read; metadata store latency exceeding the blocking timeout during auditor scans after many bookie failures.","solutions":["Inspect the RuntimeException cause for the underlying MetadataStoreException to identify timeout vs connection loss vs not-found.","Verify the underreplication hierarchy under /underreplication is intact (no manual znode deletions).","Catch the RuntimeException where you consume the iterator and rescan (the iterator is not resumable after failure).","Ensure metadata store health/latency is within BLOCKING_CALL_TIMEOUT; scale or tune the ensemble if scans repeatedly time out."],"exampleFix":"// before: letting the RuntimeException propagate and kill the auditor scan\nIterator<UnderreplicatedLedger> it = mgr.listLedgersToRereplicate(null);\nwhile (it.hasNext()) { process(it.next()); }\n\n// after: guard the iteration\ntry {\n    Iterator<UnderreplicatedLedger> it = mgr.listLedgersToRereplicate(null);\n    while (it.hasNext()) { process(it.next()); }\n} catch (RuntimeException e) {\n    log.warn(\"Scan of underreplicated ledgers failed, will retry\", e);\n}","handlingStrategy":"try-catch","validationCode":"// Java: preflight the hierarchy root before iterating\ntry {\n    store.getChildren(urLedgerPath).get(5, TimeUnit.SECONDS);\n} catch (Exception e) {\n    throw new IllegalStateException(\"Underreplication hierarchy unreadable\", e);\n}","typeGuard":null,"tryCatchPattern":"try {\n    Iterator<UnderreplicatedLedger> it = manager.listLedgersToRereplicate(predicate);\n    while (it.hasNext()) {\n        process(it.next());\n    }\n} catch (RuntimeException e) {\n    // 'Error reading list': inspect e.getCause() (MetadataStoreException) and rescan\n    log.warn(\"Underreplicated ledger listing failed\", e);\n}","preventionTips":["Always wrap iterator consumption in try-catch — failures surface lazily from hasNext()/next()","Do not manually delete or restructure urL hierarchy znodes while scans run","Keep the number of pending underreplicated ledgers bounded so scans finish inside the timeout","Verify the interrupt flag after a failed scan; interruption makes hasNext() silently return false"],"tags":["metadata-store","iterator","zookeeper","timeout","replication"],"backgroundTag":"metadata-store-unavailable","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"}