hyperledger/fabric · error
instance has not been started
Error message
instance has not been started
What it means
Instance.Stop in the externalbuilder package returns this when the instance's Session field is nil, i.e. Start() was never called (or failed) before Stop() is invoked. The instance only holds a golang.org/x/sys/exec Session after a successful Start, so Stop refuses to signal a nonexistent process.
Source
Thrown at core/container/externalbuilder/instance.go:160
}
return ccdata.ChaincodeServerInfo(i.ChaincodeServerReleaseDir())
}
func (i *Instance) Start(peerConnection *ccintf.PeerConnection) error {
sess, err := i.Builder.Run(i.PackageID, i.BldDir, peerConnection)
if err != nil {
return errors.WithMessage(err, "could not execute run")
}
i.Session = sess
return nil
}
// Stop signals the process to terminate with SIGTERM. If the process doesn't
// terminate within TermTimeout, the process is killed with SIGKILL.
func (i *Instance) Stop() error {
if i.Session == nil {
return errors.Errorf("instance has not been started")
}
done := make(chan struct{})
go func() { i.Wait(); close(done) }()
i.Session.Signal(syscall.SIGTERM)
select {
case <-time.After(i.TermTimeout):
i.Session.Signal(syscall.SIGKILL)
case <-done:
return nil
}
select {
case <-time.After(5 * time.Second):
return errors.Errorf("failed to stop instance '%s'", i.PackageID)
case <-done:
return nilView on GitHub (pinned to 2736b63f8f)
Solutions
- Check i.Session != nil (or that Start returned nil error) before calling Stop.
- Restructure lifecycle code so Stop is only called when the corresponding Start succeeded.
- If Stop is called in a defer, guard it: if inst.Session != nil { inst.Stop() }.
Example fix
// before
inst, _ := externalbuilder.NewInstance(bldr, pkgID, releaseDir)
defer inst.Stop()
// after
inst, _ := externalbuilder.NewInstance(bldr, pkgID, releaseDir)
if err := inst.Start(); err != nil {
return err
}
defer inst.Stop() Defensive patterns
Strategy: validation
Validate before calling
if inst.Session == nil {
return errors.New("instance not started; skipping stop")
}
if err := inst.Stop(); err != nil {
return err
} Type guard
func started(i *externalbuilder.Instance) bool {
return i != nil && i.Session != nil
} Prevention
- Pair every Start with a matching Stop in the success path only.
- Use defers guarded by a started flag rather than unconditional cleanup.
- Check Start()'s error before any other Instance method.
When it happens
Trigger: Calling Stop() on an &externalbuilder.Instance{} that was constructed via NewInstance but never had Start() called, or calling Stop() after Start() returned an error and left Session nil.
Common situations: Cleanup/deferred paths that call Stop unconditionally without checking whether Start succeeded; tests that build an Instance struct manually; lifecycle code that stops instances on shutdown even for ones that never launched.
Related errors
- instance was not successfully started
- panic(err)
- config ID illegal, cannot be empty
- config ID illegal, cannot be longer than %d
- name '%s' for config ID is not allowed
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/d90b9bf608e6fdf0.
Report an issue: GitHub.