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
- Catch ConflictException from the put future and retry with a fresh read (the tableview re-reads before next attempt).
- Use a distinct key per writer, or shard keys to avoid hot-key contention.
- Enable/verify the conflictResolver design accounts for optimistic-concurrency retries.
- 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
- Implement bounded retry with jitter for hot keys.
- Shard or namespace keys so concurrent writers don't CAS the same entry.
- Minimize read-modify-write windows; compute the new value quickly.
- Consider serializing writes through a single owner/leader for shared keys.
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
- Failed to update from old:%s to value:%s
- Cluster already exists
- ${duplicateBrokers} already exists in ${domainName}
- Migration is already in progress (phase: ${phase})
- Migration has already been completed
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/750d23eb9843b97f.
Report an issue: GitHub.