diff --git a/kv/coordinator.go b/kv/coordinator.go index 15db4b0c..157b8f5e 100644 --- a/kv/coordinator.go +++ b/kv/coordinator.go @@ -57,7 +57,12 @@ func (c *Coordinate) Dispatch(ctx context.Context, reqs *OperationGroup[OP]) (*C if reqs.IsTxn && reqs.StartTS == 0 { // Leader-only timestamp issuance to avoid divergence across shards. + // When the leader assigns StartTS, also clear any caller-provided + // CommitTS so dispatchTxn generates both timestamps consistently. + // A caller-supplied CommitTS without a matching StartTS could produce + // CommitTS <= StartTS (an invalid transaction). reqs.StartTS = c.nextStartTS() + reqs.CommitTS = 0 } if reqs.IsTxn { diff --git a/kv/sharded_coordinator.go b/kv/sharded_coordinator.go index 7ecc58ca..8f7a2ed9 100644 --- a/kv/sharded_coordinator.go +++ b/kv/sharded_coordinator.go @@ -70,6 +70,11 @@ func (c *ShardedCoordinator) Dispatch(ctx context.Context, reqs *OperationGroup[ return nil, err } reqs.StartTS = startTS + // When the coordinator assigns StartTS, also clear any caller-provided + // CommitTS so dispatchTxn generates both timestamps consistently. + // A caller-supplied CommitTS without a matching StartTS could produce + // CommitTS <= StartTS (an invalid transaction). + reqs.CommitTS = 0 } if reqs.IsTxn {