hyperledger/fabric · error

txid: %s(%s) exists

Error message

txid: %s(%s) exists

What it means

TransactionContexts.Create refuses to create a transaction context when one already exists for the same channel+txid key. Each transaction may be processed only once concurrently; a duplicate context means the same transaction ID is being launched twice.

Source

Thrown at core/chaincode/transaction_contexts.go:45

		contexts: map[string]*TransactionContext{},
	}
}

// contextID creates a transaction identifier that is scoped to a channel.
func contextID(channelID, txID string) string {
	return channelID + txID
}

// Create creates a new TransactionContext for the specified channel and
// transaction ID. An error is returned when a transaction context has already
// been created for the specified channel and transaction ID.
func (c *TransactionContexts) Create(txParams *ccprovider.TransactionParams) (*TransactionContext, error) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	ctxID := contextID(txParams.ChannelID, txParams.TxID)
	if c.contexts[ctxID] != nil {
		return nil, errors.Errorf("txid: %s(%s) exists", txParams.TxID, txParams.ChannelID)
	}

	txctx := &TransactionContext{
		NamespaceID:          txParams.NamespaceID,
		ChannelID:            txParams.ChannelID,
		SignedProp:           txParams.SignedProp,
		Proposal:             txParams.Proposal,
		ResponseNotifier:     make(chan *pb.ChaincodeMessage, 1),
		TXSimulator:          txParams.TXSimulator,
		HistoryQueryExecutor: txParams.HistoryQueryExecutor,
		CollectionStore:      txParams.CollectionStore,
		IsInitTransaction:    txParams.IsInitTransaction,

		queryIteratorMap:    map[string]commonledger.ResultsIterator{},
		pendingQueryResults: map[string]*PendingQueryResult{},
	}
	txctx.InitializeCollectionACLCache()

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Retry the transaction with a freshly computed, unique transaction ID (let the SDK generate it)
  2. Check for stuck pending transactions in peer logs; restart the peer if a context leaked
  3. Verify no client-side code reuses a txid across submission retries
  4. If duplicate delivery is suspected, inspect the ordering service/deliver client configuration

Example fix

// before: client retries with same txid
submit(tx, txid)
submit(tx, txid)  // -> txid exists
// after
submit(tx, newTxID())
submit(tx, newTxID())  // on retry
Defensive patterns

Strategy: try-catch

Validate before calling

// SDK-side: always generate a fresh txid
if txID == "" || seenTxIDs[txID] { txID = computeNewTxID(creator, nonce) }

Try / catch

if err := cc.Invoke(txParams); err != nil && strings.Contains(err.Error(), "exists") {
    // regenerate txid and resubmit, or wait for the in-flight tx to complete
}

Prevention

When it happens

Trigger: A message with the same ChannelID+TxID is delivered to the chaincode handler while a context for it already exists — e.g., duplicate delivery of the same transaction by the Deliver service, or a client retrying with a reused txid.

Common situations: Replayed/retried transaction submission reusing the same transaction ID; eventing bugs delivering a transaction twice; a stuck previous invocation whose context was never removed (processTransaction never completed) blocking reuse.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/da92ff71321dbbe2. Report an issue: GitHub.