apache/pulsar · error · ConflictException

Failed to update to value:%s

Error message

Failed to update to value:%s

What it means

ConflictException thrown by MetadataStoreTableViewImpl.put when the underlying metadata-store update fails with BadVersionException, meaning another writer changed the entry between the cached read and the CAS update attempt.

Source

Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/tableview/impl/MetadataStoreTableViewImpl.java:418

    }

    public T get(String key) {
        return data.get(key);
    }

    public CompletableFuture<Void> put(String key, T value) {
        String path = getPath(key);
        return cache.readModifyUpdateOrCreate(path, (old) -> {
            if (conflictResolver.test(old.orElse(null), value)) {
                return value;
            } else {
                throw new ConflictException(
                        String.format("Failed to update from old:%s to value:%s", old, value));
            }
        }).thenCompose(__ -> doHandleNotification(path)) // immediately notify local tableview
        .exceptionally(e -> {
            if (e.getCause() instanceof MetadataStoreException.BadVersionException) {
                throw FutureUtil.wrapToCompletionException(new ConflictException(
                        String.format("Failed to update to value:%s", value)));
            }

            throw FutureUtil.wrapToCompletionException(e.getCause());
        });
    }

    public CompletableFuture<Void> delete(String key) {
        String path = getPath(key);
        return cache.delete(path)
                .thenCompose(__ -> doHandleNotification(path)); // immediately notify local tableview
    }

    public int size() {
        return immutableData.size();
    }

    public boolean isEmpty() {

View on GitHub (pinned to 820761864e)

Solutions

  1. Catch ConflictException from the put future and retry with a fresh read (the tableview re-reads before next attempt).
  2. Use a distinct key per writer, or shard keys to avoid hot-key contention.
  3. Enable/verify the conflictResolver design accounts for optimistic-concurrency retries.
  4. Reduce write frequency to the same key, or serialize writes through a single owner.

Example fix

// before
return cache.readModifyUpdateOrCreate(path, mutator);
// after
return FutureUtil.retryFailedAsync(() -> cache.readModifyUpdateOrCreate(path, mutator), retryPolicy);
Defensive patterns

Strategy: retry

Try / catch

CompletableFuture<Void> put = tableView.put(key, value);
put.exceptionally(ex -> {
    if (FutureUtil.unwrapCompletionException(ex) instanceof ConflictException) {
        // BadVersion case: retry after fresh read with backoff
        return null;
    }
    throw FutureUtil.wrapToCompletionException(ex);
});

Prevention

When it happens

Trigger: Two clients call put on the same key concurrently; the second update's expected version no longer matches the store's version, so cache.readModifyUpdateOrCreate fails with MetadataStoreException.BadVersionException and is translated into this ConflictException.

Common situations: Multiple brokers/producers writing the same tableview key at once, a delete racing with a put on the same key, or retry loops that hammer one hot key.

Related errors


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