{"record":{"id":"2c99b667af70a946","repo":"apache/pulsar","slug":"failed-to-check-if-ledger-is-beinge-replicated","errorCode":null,"errorMessage":"Failed to check if ledger is beinge replicated","messagePattern":"Failed to check if ledger is beinge replicated","errorType":"exception","errorClass":"ReplicationException.UnavailableException","httpStatus":null,"severity":"error","filePath":"pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java","lineNumber":802,"sourceCode":"            log.error().exception(ee).log(\"Error while checking the state of ledger re-replication\");\n            throw new ReplicationException.UnavailableException(\n                    \"Error contacting zookeeper\", ee);\n        } catch (InterruptedException ie) {\n            Thread.currentThread().interrupt();\n            throw new ReplicationException.UnavailableException(\n                    \"Interrupted while contacting zookeeper\", ie);\n        }\n    }\n\n    /**\n     * Check whether the ledger is being replicated by any bookie.\n     */\n    @Override\n    public boolean isLedgerBeingReplicated(long ledgerId) throws ReplicationException {\n        try {\n            return store.exists(getUrLedgerLockPath(urLockPath, ledgerId)).get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n        } catch (Exception e) {\n            throw new ReplicationException.UnavailableException(\"Failed to check if ledger is beinge replicated\", e);\n        }\n    }\n\n    @Override\n    public boolean initializeLostBookieRecoveryDelay(int lostBookieRecoveryDelay) throws\n            ReplicationException.UnavailableException {\n        log.debug(\"initializeLostBookieRecoveryDelay()\");\n        try {\n            store.put(lostBookieRecoveryDelayPath, Integer.toString(lostBookieRecoveryDelay).getBytes(UTF_8),\n                    Optional.of(-1L)).get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);\n        } catch (ExecutionException ee) {\n            if (ee.getCause() instanceof MetadataStoreException.BadVersionException) {\n                log.info(\"lostBookieRecoveryDelay node is already present, so using existing value\");\n                return false;\n            } else {\n                log.error().exception(ee).log(\"Error while initializing LostBookieRecoveryDelay\");\n                throw new ReplicationException.UnavailableException(\"Error contacting zookeeper\", ee);\n            }","sourceCodeStart":784,"sourceCodeEnd":820,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerUnderreplicationManager.java#L784-L820","documentation":"Thrown by isLedgerBeingReplicated(ledgerId) when the blocking exists() check on the per-ledger underreplication lock path (getUrLedgerLockPath(urLockPath, ledgerId)) fails for any reason. This method tells whether a given ledger is currently being re-replicated by a bookie; any store error or timeout is wrapped into ReplicationException.UnavailableException. Note the message contains a typo ('beinge') kept for API compatibility.","triggerScenarios":"Calling isLedgerBeingReplicated(ledgerId) while the metadata store is down, the lock-path lookup fails (e.g. metadata service error), or the call exceeds BLOCKING_CALL_TIMEOUT. Unlike sibling methods, this catches all Exceptions including RuntimeException.","commonSituations":"Recovery tooling checking replication progress during a ZooKeeper outage; ledger id formatting producing a valid path but the store being unreachable; monitoring dashboards hitting this per-ledger check at scale and timing out.","solutions":["Verify metadata store health and connectivity first.","Inspect the wrapped cause (getCause()) to distinguish store outage from bad ledger-id/path issues.","Retry with backoff; the check is read-only.","Reduce per-ledger polling frequency if timeouts come from load."],"exampleFix":"// before\nboolean replicating = urManager.isLedgerBeingReplicated(ledgerId);\n// after\nboolean replicating;\ntry {\n    replicating = urManager.isLedgerBeingReplicated(ledgerId);\n} catch (ReplicationException.UnavailableException e) {\n    log.warn(\"Cannot check replication state for ledger {}, treating as not replicating\", ledgerId, e);\n    replicating = false;\n}","handlingStrategy":"try-catch","validationCode":"// validate store liveness and sane ledgerId before the per-ledger check\nif (ledgerId < 0) throw new IllegalArgumentException(\"bad ledgerId\");\nstore.exists(\"/probe\").get(5, TimeUnit.SECONDS);","typeGuard":"Optional<Boolean> safeIsBeingReplicated(LedgerUnderreplicationManager m, long ledgerId) {\n    try { return Optional.of(m.isLedgerBeingReplicated(ledgerId)); }\n    catch (ReplicationException.UnavailableException e) { return Optional.empty(); }\n}","tryCatchPattern":"try {\n    replicating = urManager.isLedgerBeingReplicated(ledgerId);\n} catch (ReplicationException.UnavailableException e) {\n    // conservative default: assume not replicating, log cause for triage\n    replicating = false;\n}","preventionTips":["Throttle per-ledger replication-state polling to avoid metadata store timeouts.","Check getCause() to distinguish outage from path/ledger-id issues.","Keep the metadata store healthy: monitor latency and quorum before bulk recovery tooling runs."],"tags":["metadata-store","zookeeper","ledger-replication","timeout"],"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-14T05:17:10.506Z"}