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 nil

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check i.Session != nil (or that Start returned nil error) before calling Stop.
  2. Restructure lifecycle code so Stop is only called when the corresponding Start succeeded.
  3. 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

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


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