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
- Retry the transaction with a freshly computed, unique transaction ID (let the SDK generate it)
- Check for stuck pending transactions in peer logs; restart the peer if a context leaked
- Verify no client-side code reuses a txid across submission retries
- 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
- Never reuse transaction IDs across retries
- Let the SDK generate txids from creator+nonce
- Handle stuck transactions (timeout -> resubmit with new txid)
- Check for duplicate delivery in event/replay tooling
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
- chaincode already successfully installed (package ID '%s')
- lock is already acquired on file %s
- failed to execute transaction %s
- timeout expired while executing transaction
- duplicate chaincodeID: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/da92ff71321dbbe2.
Report an issue: GitHub.