hyperledger/fabric · warning
could not find handler: %s
Error message
could not find handler: %s
What it means
Returned by HandlerRegistry.Deregister when no handler exists for the given chaincodeID in the registry. The peer looked up r.handlers[ccid], found nil, and refuses to close/deregister a handler that was never (or no longer) registered.
Source
Thrown at core/chaincode/handler_registry.go:163
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 {
chaincodeLogger.Debugf("deregister handler: %s", ccid)
r.mutex.Lock()
handler := r.handlers[ccid]
delete(r.handlers, ccid)
delete(r.launching, ccid)
r.mutex.Unlock()
if handler == nil {
return errors.Errorf("could not find handler: %s", ccid)
}
handler.Close()
chaincodeLogger.Debugf("deregistered handler with key: %s", ccid)
return nil
}
type TxQueryExecutorGetter struct {
HandlerRegistry *HandlerRegistry
CCID string
}
func (g *TxQueryExecutorGetter) TxQueryExecutor(chainID, txID string) ledger.SimpleQueryExecutor {
handler := g.HandlerRegistry.Handler(g.CCID)
if handler == nil {
return nil
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the chaincodeID passed to Deregister matches one that is currently registered.
- Treat the error as benign in cleanup paths — log and continue if the handler is already gone.
- Check for double-close/double-deregister logic in the shutdown path and guard it.
- Capture peer logs around chaincode exit to find why the handler was missing (crash before full registration).
Example fix
// cleanup path
// before
if err := registry.Deregister(ccid); err != nil { return err }
// after
if err := registry.Deregister(ccid); err != nil {
logger.Debugf("deregister skipped: %v", err) // handler already gone
} Defensive patterns
Strategy: try-catch
Try / catch
if err := registry.Deregister(ccid); err != nil && strings.Contains(err.Error(), "could not find handler") {
// benign: handler already gone; log at debug and continue cleanup
} Prevention
- Idempotent cleanup: treat missing-handler deregistration as success.
- Guard shutdown paths against double-deregistration.
- Correlate chaincode exit logs with peer deregistration logs to spot race conditions.
When it happens
Trigger: Deregister(ccid) is called for a chaincodeID not present in r.handlers — e.g. double deregistration, deregistering a chaincode that never registered, or after the registry entry was already deleted.
Common situations: Chaincode connection closes twice (handler cleanup race); peer restarting while a chaincode exits and calls deregister; a launch failure path deregistering a handler that failed registration; tests calling Deregister with a fabricated chaincodeID.
Related errors
- instance has not yet been built, cannot get chaincode server
- instance has not yet been built, cannot be stopped
- instance has not yet been built, cannot wait
- failed listing installed chaincodes
- failed to parse collection config
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/e7abb4da43e44e38.
Report an issue: GitHub.