apache/pulsar · error · RuntimeException

is not an instance of MetadataStore

Error message

 is not an instance of MetadataStore

What it means

BookieRackAffinityMapping.getMetadataStore reads the METADATA_STORE_INSTANCE property from the BookKeeper configuration. If that property is set but holds an object that is not a MetadataStore (wrong type injected programmatically), a RuntimeException naming the property is thrown.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/bookie/rackawareness/BookieRackAffinityMapping.java:78

public class BookieRackAffinityMapping extends AbstractDNSToSwitchMapping
        implements RackChangeNotifier {

    public static final String BOOKIE_INFO_ROOT_PATH = "/bookies";
    public static final String METADATA_STORE_INSTANCE = "METADATA_STORE_INSTANCE";

    private MetadataCache<BookiesRackConfiguration> bookieMappingCache = null;
    private volatile ITopologyAwareEnsemblePlacementPolicy<BookieNode> rackawarePolicy = null;
    private List<BookieId> bookieAddressListLastTime = new ArrayList<>();

    private BookiesRackConfiguration racksWithHost = new BookiesRackConfiguration();
    private Map<String, BookieInfo> bookieInfoMap = new HashMap<>();

    static MetadataStore getMetadataStore(Configuration conf) throws MetadataException {
        MetadataStore store;
        Object storeProperty = conf.getProperty(METADATA_STORE_INSTANCE);
        if (storeProperty != null) {
            if (!(storeProperty instanceof MetadataStore)) {
                throw new RuntimeException(METADATA_STORE_INSTANCE + " is not an instance of MetadataStore");
            }
            store = (MetadataStore) storeProperty;
        } else {
            String url;
            String metadataServiceUri = ConfigurationStringUtil.castToString(conf.getProperty("metadataServiceUri"));
            if (StringUtils.isNotBlank(metadataServiceUri)) {
                try {
                    url = metadataServiceUri.replaceFirst(METADATA_STORE_SCHEME + ":", "")
                            .replace(";", ",");
                } catch (Exception e) {
                    throw new MetadataException(Code.METADATA_SERVICE_ERROR, e);
                }
            } else {
                String zkServers = ConfigurationStringUtil.castToString(conf.getProperty("zkServers"));
                if (StringUtils.isBlank(zkServers)) {
                    String errorMsg = String.format("Neither %s configuration set in the BK client configuration nor "
                            + "metadataServiceUri/zkServers set in bk server configuration", METADATA_STORE_INSTANCE);
                    throw new RuntimeException(errorMsg);

View on GitHub (pinned to 820761864e)

Solutions

  1. Set METADATA_STORE_INSTANCE to an actual org.apache.pulsar.metadata.api.MetadataStore instance
  2. Or remove the property and supply metadataServiceUri / zkServers so the store is created from a URI
  3. Check the injected object is not a mock/wrapper — use MetadataStoreExtended.create() to build it

Example fix

// before
conf.setProperty(METADATA_STORE_INSTANCE, mockStoreBuilder); // wrong type
// after
MetadataStore store = MetadataStoreExtended.create("zk+sasl://zk1:2181/ledgers", ...);
conf.setProperty(METADATA_STORE_INSTANCE, store);
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = conf.getProperty(METADATA_STORE_INSTANCE);
if (v != null && !(v instanceof MetadataStore)) {
    throw new IllegalArgumentException("METADATA_STORE_INSTANCE must be a MetadataStore");
}

Type guard

static boolean isValidStore(Object o) {
    return o == null || o instanceof MetadataStore;
}

Try / catch

try {
    mapping.setConf(conf);
} catch (RuntimeException e) {
    log.error("bad METADATA_STORE_INSTANCE", e);
}

Prevention

When it happens

Trigger: A Configuration passed to setConf()/initialize() contains METADATA_STORE_INSTANCE bound to an object of a type other than MetadataStore — only possible via programmatic configuration, not string config files.

Common situations: Embedding BookKeeper/Pulsar in tests or custom code and passing a mock, a different store implementation, or a Supplier/wrapper object under that key; type changes across library versions.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/f0611bf6edc8cb65. Report an issue: GitHub.