apache/pulsar · warning · LedgerLayoutExistsException
LedgerLayoutExistsException
Error message
LedgerLayoutExistsException
What it means
LedgerLayoutExistsException is thrown by storeLedgerLayout when the metadata put with expected version -1 fails with MetadataStoreException.BadVersionException, meaning the layout node already exists. This is BookKeeper's conditional-create semantics: the layout may only be written once; the exception is part of the LayoutManager contract.
Source
Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLayoutManager.java:82
throw new IOException(e);
}
}
@Override
public void storeLedgerLayout(LedgerLayout ledgerLayout) throws IOException {
try {
byte[] layoutData = ledgerLayout.serialize();
store.put(layoutPath, layoutData, Optional.of(-1L))
.get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
} catch (TimeoutException e) {
throw new IOException(e);
} catch (ExecutionException e) {
if (e.getCause() instanceof MetadataStoreException.BadVersionException) {
throw new LedgerLayoutExistsException(e);
} else {
throw new IOException(e);
}
}
}
@Override
public void deleteLedgerLayout() throws IOException {
try {
store.delete(layoutPath, Optional.empty())
.get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
} catch (ExecutionException | TimeoutException e) {
throw new IOException(e);
}
}View on GitHub (pinned to 820761864e)
Solutions
- Treat LedgerLayoutExistsException as benign when re-initializing: call readLedgerLayout() to load and validate the existing layout instead of storing a new one.
- Ensure only one component performs initial layout creation (serialize cluster bootstrap).
- If the existing layout is wrong or from another cluster, deliberately delete it with deleteLedgerLayout() and re-store — only after confirming the ledgers root is unused/migratable.
Example fix
// before
layoutManager.storeLedgerLayout(layout);
// after
try {
layoutManager.storeLedgerLayout(layout);
} catch (LedgerLayoutExistsException e) {
LedgerLayout existing = layoutManager.readLedgerLayout();
if (!existing.equals(layout)) {
throw new IOException("Layout mismatch with existing cluster layout", e);
}
} Defensive patterns
Strategy: validation
Validate before calling
LedgerLayout existing = layoutManager.readLedgerLayout();
if (existing != null && !existing.equals(newLayout)) {
throw new IllegalStateException("Ledger layout already exists and differs");
} Type guard
boolean layoutMatchesExisting(PulsarLayoutManager lm, LedgerLayout desired) {
try { return desired.equals(lm.readLedgerLayout()); }
catch (IOException missing) { return false; } // no layout yet
} Try / catch
try {
layoutManager.storeLedgerLayout(layout);
} catch (LedgerLayoutExistsException e) {
// idempotent bootstrap: verify and continue
if (!layout.equals(layoutManager.readLedgerLayout())) throw new IOException("layout mismatch", e);
} Prevention
- Serialize cluster bootstrap so only one node creates the layout.
- Check readLedgerLayout() before writing when reusing an existing ledgers root.
- Never point a new cluster at a ledgersRootPath that already contains a layout without verifying it.
When it happens
Trigger: Two concurrent BookKeeper clients (or two broker starts) both attempt storeLedgerLayout with expect -1; one wins and the other gets BadVersionException converted to LedgerLayoutExistsException. Also occurs on re-initialization against a metadata store that already holds a layout.
Common situations: Starting a second broker against an already-initialized metadata store; race between multiple BookKeeper client instances; replaying an initialization script; connecting a new cluster to a ledgers root that already has a layout (e.g., after switching ledgersRootPath or reusing a ZooKeeper chroot).
Related errors
- IOException
- Incompatible layout found (LAYOUT:1)
- Invalid data found
- Cursor %s mark-delete position %s is ahead of the last posit
- Timeout during managed ledger close
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/1fb0e0d6588d6841.
Report an issue: GitHub.