thanos-io/thanos · error
conflict
Error message
conflict
What it means
errConflict is the sentinel returned by Write and receiveOTLPHTTP whenever a write fails due to a conflict-type error (e.g. the target considers the series/operation conflicting). The HTTP handler maps it to http.StatusConflict (409) and the capnp server maps it to writecapnp.WriteError_alreadyExists. It is matched with errors.Cause, so it must be the root cause of the returned error.
Solutions
- Check which peer returned the conflict and inspect its logs for the underlying store error
- Make the write idempotent on the client or deduplicate retries before resending
- Verify all receiver replicas share a consistent hashring configuration so conflicting writes don't occur
- If you need programmatic handling, compare with errors.Cause(err) == errConflict / errors.Is where wrapping permits
Example fix
// before
if err := r.Write(ctx, req); err != nil { return err }
// after
if err := r.Write(ctx, req); err != nil {
if errors.Is(errors.Cause(err), errConflict) {
return status.Error(codes.AlreadyExists, err.Error())
}
return err
} Defensive patterns
Strategy: try-catch
Type guard
func isConflict(err error) bool {
return errors.Is(errors.Cause(err), errConflict)
} Try / catch
err := r.Write(ctx, req)
if err != nil {
switch errors.Cause(err) {
case errConflict: http.Error(w, err.Error(), http.StatusConflict)
default: http.Error(w, err.Error(), http.StatusInternalServerError)
}
} Prevention
- Compare root causes with errors.Cause/errors.Is, since these sentinels are wrapped
- Make client writes idempotent to tolerate duplicate delivery
- Keep the hashring consistent across all receivers to avoid conflicting writes
- Back off retries instead of immediately re-sending conflicting writes
When it happens
Trigger: Write or receiveOTLPHTTP returns an error whose root cause is errConflict — a replication target or local store reports a conflicting write that is not a validation, unavailability, or bad-replica error.
Common situations: Duplicate/overlapping writes racing on the same series, miswired replication producing out-of-order conflicting state between receiver replicas, clients retrying writes the target already committed.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/c26458d9d6ce7068.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/receive/handler.go:89
// AllTenantsQueryParam is the query parameter for getting TSDB stats for all tenants.
AllTenantsQueryParam = "all_tenants"
// LimitStatsQueryParam is the query parameter for limiting the amount of returned TSDB stats.
LimitStatsQueryParam = "limit"
// Labels for metrics.
labelSuccess = "success"
labelError = "error"
)
type ReplicationProtocol string
const (
ProtobufReplication ReplicationProtocol = "protobuf"
CapNProtoReplication ReplicationProtocol = "capnproto"
)
var (
// errConflict is returned whenever an operation fails due to any conflict-type error.
errConflict = errors.New("conflict")
errBadReplica = errors.New("request replica exceeds receiver replication factor")
errNotReady = errors.New("target not ready")
errUnavailable = errors.New("target not available")
errValidation = errors.New("validation error")
)
type WriteableStoreAsyncClient interface {
storepb.WriteableStoreClient
RemoteWriteAsync(context.Context, *storepb.WriteRequest, endpointReplica, []int, chan writeResponse, func(error))
// TryRemoteWriteAsync submits the request without blocking. Returns false if the peer's
// worker pool is at capacity; the caller should fall back to RemoteWriteAsync.
TryRemoteWriteAsync(context.Context, *storepb.WriteRequest, endpointReplica, []int, chan writeResponse, func(error)) bool
}
// Options for the web Handler.
type Options struct {View on GitHub (pinned to 35b8b99117)