apache/pulsar · critical · IOException
Incompatible layout version found : ${factoryVersion}
Error message
Incompatible layout version found : ${factoryVersion} What it means
PulsarLedgerManagerFactory.initialize reads the stored layout version from the metadata store and requires it to equal CUR_VERSION. If the metadata store holds a layout written by a different (older or newer) BookKeeper/Pulsar version, initialization aborts with this IOException to prevent corrupting ledgers metadata with an incompatible format.
Source
Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/PulsarLedgerManagerFactory.java:61
private static final int CUR_VERSION = 1;
@SuppressWarnings("rawtypes")
private AbstractConfiguration conf;
private MetadataStoreExtended store;
private String ledgerRootPath;
@SuppressWarnings("rawtypes")
@Override
public LedgerManagerFactory initialize(AbstractConfiguration conf, LayoutManager layoutManager,
int factoryVersion) throws IOException {
checkArgument(layoutManager instanceof PulsarLayoutManager);
PulsarLayoutManager pulsarLayoutManager = (PulsarLayoutManager) layoutManager;
if (CUR_VERSION != factoryVersion) {
throw new IOException("Incompatible layout version found : " + factoryVersion);
}
this.conf = conf;
this.store = pulsarLayoutManager.getStore();
this.ledgerRootPath = pulsarLayoutManager.getLedgersRootPath();
return this;
}
@Override
public void close() throws IOException {
// since metadata store instance is passed from outside
// we don't need to close it here
}
@Override
public int getCurrentVersion() {
return CUR_VERSION;
}
View on GitHub (pinned to 820761864e)
Solutions
- Check the stored layout version in the metadata store (LAYOUT znode under the ledgers root) and align your Pulsar/BookKeeper version with it.
- Complete a proper rolling upgrade so all components use the version that wrote the layout.
- If the store is stale test/dev data, re-provision the ledgers root (nuke and re-create) after confirming no ledgers are needed.
- Never hand-edit the layout znode; use supported migration/upgrade tooling.
Defensive patterns
Strategy: validation
Validate before calling
byte[] layout = store.get(layoutPath).join().get().getValue(); // decode the stored factory version and assert it matches the expected CUR_VERSION before initialize()
Try / catch
try {
factory.initialize(conf, layoutManager, layoutManager, 1 /* current layout version */);
} catch (IOException e) {
throw new IllegalStateException("Metadata store layout version incompatible with this build: " + e.getMessage(), e);
} Prevention
- Pin all Pulsar/BookKeeper components in a cluster to the same version.
- Check the stored layout version before and after rolling upgrades.
- Never share one metadata store between clusters running different versions.
- Validate backups/snapshots against the running version before restoring.
When it happens
Trigger: Calling LedgerManagerFactory.initialize when the LAYOUT znode in the metadata store contains a factory version != CUR_VERSION — typically after upgrading or downgrading the broker/bookkeeper stack or pointing a cluster at a store created by another version.
Common situations: Rolling upgrades with mixed versions; reusing a metadata store from an old Pulsar deployment with a new broker; restoring a metadata snapshot from a different release; running a client against a cluster provisioned by a much newer Pulsar.
Related errors
- METADATA_SERVICE_ERROR
- The path ${path} doesn't look like a valid path for a Bookie
- IOException
- IOException
- it is not a valid hashed path name : ${ledgerPath}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/0e41ff7b002c705a.
Report an issue: GitHub.