TransactionException getTransactionException(KeyInfo keyInfo, GemFireException e) {
    if (isRealDealLocal() && !buckets.isEmpty() && !buckets.containsKey(keyInfo.getBucketId())) {
      return new TransactionDataNotColocatedException(
          String.format("Key %s is not colocated with transaction",
              keyInfo.getKey()),
          e.getCause());
    }
    Throwable ex = e;
    while (ex != null) {
      if (ex instanceof PrimaryBucketException) {
        if (isRealDealLocal() && !firstOperationOnPartitionedRegion) {
          return new TransactionDataNotColocatedException(
              String.format(
                  "Key %s is not colocated with transaction. First operation in a transaction "
                      + "should be on a partitioned region when there are operations on both "
                      + "partitioned regions and replicate regions.",
                  keyInfo.getKey()));
        }
        return new TransactionDataRebalancedException(
            "Transactional data moved, due to rebalancing.");
      }
      ex = ex.getCause();
    }
    return (TransactionException) e;
  }
This returns either the TXState for the current transaction or a proxy for the state if it is
held in another member. If no state currently exists, one is created

@param key the key of the entry that is currently being modified
@param r the region that is currently being modified
@return the state or a proxy for the state
geode-core/src/main/java/org/apache/geode/internal/cache/TXStateProxyImpl.java