hyperledger/fabric · error

duplicate chaincodeID: %s

Error message

duplicate chaincodeID: %s

What it means

Returned by HandlerRegistry.Register when a chaincode handler tries to register a chaincodeID that already has a live registered handler. Each running chaincode instance must register exactly once per chaincodeID; a second registration means two containers claim the same chaincode.

Source

Thrown at core/chaincode/handler_registry.go:135

// Handler retrieves the handler for a chaincode instance.
func (r *HandlerRegistry) Handler(ccid string) *Handler {
	r.mutex.Lock()
	h := r.handlers[ccid]
	r.mutex.Unlock()
	return h
}

// Register adds a chaincode handler to the registry.
// An error will be returned if a handler is already registered for the
// chaincode. An error will also be returned if the chaincode has not already
// been "launched", and unsolicited registration is not allowed.
func (r *HandlerRegistry) Register(h *Handler) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	if r.handlers[h.chaincodeID] != nil {
		chaincodeLogger.Debugf("duplicate registered handler(key:%s) return error", h.chaincodeID)
		return errors.Errorf("duplicate chaincodeID: %s", h.chaincodeID)
	}

	// This chaincode was not launched by the peer but is attempting
	// to register. Only allowed in development mode.
	if r.launching[h.chaincodeID] == nil && !r.allowUnsolicitedRegistration {
		return errors.Errorf("peer will not accept external chaincode connection %s (except in dev mode)", h.chaincodeID)
	}

	r.handlers[h.chaincodeID] = h

	chaincodeLogger.Debugf("registered handler complete for chaincode %s", h.chaincodeID)
	return nil
}

// Deregister clears references to state associated specified chaincode.
// As part of the cleanup, it closes the handler so it can cleanup any state.
// If the registry does not contain the provided handler, an error is returned.
func (r *HandlerRegistry) Deregister(ccid string) error {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Stop and remove the stale chaincode container (docker rm -f <chaincode-container>) and retry.
  2. Restart the peer to clear the stale handler registry entry if containers are already gone.
  3. In dev mode, ensure only one chaincode process connects with a given chaincodeID.
  4. Check for orphaned containers from previous launches and clean them up (docker ps -a).

Example fix

// before: start chaincode while old one still running
CORE_CHAINCODE_ID_NAME=mycc:1.0 peer chaincode launch ...
// after
docker rm -f $(docker ps -aq --filter name=dev-peer-mycc)
CORE_CHAINCODE_ID_NAME=mycc:1.0 peer chaincode launch ...
Defensive patterns

Strategy: validation

Validate before calling

// before starting a chaincode container, ensure no instance is running
docker ps --filter name=dev-peer --filter status=running
# stop stale containers first:
docker rm -f $(docker ps -aq --filter name=dev-peer-mycc)

Prevention

When it happens

Trigger: A second chaincode container/process connects to the peer and calls Register with a chaincodeID whose entry in r.handlers is non-nil (the first handler is still connected).

Common situations: Old chaincode container still alive while a new one starts (stale docker container); restarting chaincode without the peer releasing the old handler; launching the same chaincode twice manually (e.g. dev mode double-start); orphaned containers after peer restart.

Related errors


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