hyperledger/fabric · error · ErrLedgerAlreadyOpened

ledger already opened

Error message

ledger already opened

What it means

ErrLedgerAlreadyOpened is a sentinel error returned by LedgerMgr.OpenLedger when the requested channel's ledger is already present in the manager's openedLedgers map, since each ledger may only be opened once per manager instance. It prevents duplicate handles to the same underlying ledger, which would corrupt state coordination.

Source

Thrown at core/ledger/ledgermgmt/ledger_mgmt.go:29

	"fmt"
	"sync"

	"github.com/hyperledger/fabric-lib-go/common/flogging"
	"github.com/hyperledger/fabric-lib-go/common/metrics"
	"github.com/hyperledger/fabric-protos-go-apiv2/common"
	pb "github.com/hyperledger/fabric-protos-go-apiv2/peer"
	"github.com/hyperledger/fabric/core/common/ccprovider"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/core/ledger/cceventmgmt"
	"github.com/hyperledger/fabric/core/ledger/kvledger"
	"github.com/hyperledger/fabric/internal/fileutil"
	"github.com/pkg/errors"
)

var logger = flogging.MustGetLogger("ledgermgmt")

// ErrLedgerAlreadyOpened is thrown by a CreateLedger call if a ledger with the given id is already opened
var ErrLedgerAlreadyOpened = errors.New("ledger already opened")

// ErrLedgerMgmtNotInitialized is thrown when ledger mgmt is used before initializing this
var ErrLedgerMgmtNotInitialized = errors.New("ledger mgmt should be initialized before using")

// LedgerMgr manages ledgers for all channels
type LedgerMgr struct {
	creationLock         sync.Mutex
	joinBySnapshotStatus *pb.JoinBySnapshotStatus

	lock           sync.Mutex
	openedLedgers  map[string]ledger.PeerLedger
	ledgerProvider ledger.PeerLedgerProvider

	ebMetadataProvider MetadataProvider
}

type MetadataProvider interface {
	PackageMetadata(ccid string) ([]byte, error)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Track which ledger ids are already opened and reuse the existing PeerLedger handle instead of calling OpenLedger again.
  2. Compare against the exported sentinel with errors.Is(err, ledgermgmt.ErrLedgerAlreadyOpened) and treat it as 'already have it' rather than a fatal failure.
  3. Call CloseLedger for the open ledger before attempting to reopen it, if reopening is genuinely required.

Example fix

// before
l, err := ledgerMgr.OpenLedger(chanID)
if err != nil {
    return err
}

// after
l, err := ledgerMgr.OpenLedger(chanID)
if err != nil {
    if errors.Is(err, ledgermgmt.ErrLedgerAlreadyOpened) {
        l = existingHandles[chanID] // reuse cached handle
        return nil
    }
    return err
}
Defensive patterns

Strategy: type-guard

Validate before calling

// keep a set of already-opened ledgers
if _, open := openedLedgers[chanID]; open {
    return openedLedgers[chanID], nil // skip OpenLedger
}

Type guard

func IsLedgerAlreadyOpened(err error) bool {
    return errors.Is(err, ledgermgmt.ErrLedgerAlreadyOpened)
}

Try / catch

lgr, err := ledgerMgr.OpenLedger(chanID)
if err != nil {
    if errors.Is(err, ledgermgmt.ErrLedgerAlreadyOpened) {
        return cachedLedgerHandle(chanID), nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling OpenLedger(id) twice for the same ledger/channel id without closing the first instance; a channel created via CreateLedger and then opened again; test code calling OpenLedger on an already-open ledger.

Common situations: Applications caching ledger handles then re-invoking OpenLedger on channel join or reconnection; race between two goroutines opening the same channel; event handlers firing OpenLedger redundantly after the ledger was already opened at creation.

Related errors


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