hyperledger/fabric · error

invalid channel-less operation

Error message

invalid channel-less operation

What it means

DummyQueryExecutorShim is a placeholder query executor (per the source comment) used for channel-less system chaincode operations like _lifecycle's InstallChaincode; its GetState always returns this fixed error. It exists purely to make channel-less calls fail cleanly instead of panicking — e.g., an InstallChaincode invocation attempted against a chaincode other than _lifecycle.

Source

Thrown at core/chaincode/lifecycle/ledger_shim.go:189

	State      PrivateQueryExecutor
}

func (pqes *PrivateQueryExecutorShim) GetStateHash(key string) ([]byte, error) {
	return pqes.State.GetPrivateDataHash(pqes.Namespace, pqes.Collection, key)
}

func (pqes *PrivateQueryExecutorShim) CollectionName() string {
	return pqes.Collection
}

// DummyQueryExecutorShim implements the ReadableState interface. It is
// used to ensure channel-less system chaincode calls don't panic and return
// and error when an invalid operation is attempted (i.e. an InstallChaincode
// invocation against a chaincode other than _lifecycle)
type DummyQueryExecutorShim struct{}

func (*DummyQueryExecutorShim) GetState(key string) ([]byte, error) {
	return nil, errors.New("invalid channel-less operation")
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Do not use DummyQueryExecutorShim for state-reading operations; route chaincode invocations through a real channel context (GetQueryExecutorForChannel).
  2. Ensure channel-less system chaincode calls target only _lifecycle and never attempt ledger reads.
  3. In application code, always invoke chaincode with a valid channelID so a real query executor backs state access.

Example fix

// before: channel-less shim used for state read
shim := &lifecycle.DummyQueryExecutorShim{}
val, _ := shim.GetState(key) // always errors
// after: obtain executor from a real channel
qe, err := ledger.GetQueryExecutorForChannel(channelID)
val, err = qe.GetState(namespace, key)
Defensive patterns

Strategy: validation

Validate before calling

// Go: only route channel-less lifecycle calls to _lifecycle
func checkChannelLess(cc string) error {
  if cc != "_lifecycle" {
    return fmt.Errorf("channel-less operation only valid for _lifecycle, got %s", cc)
  }
  return nil
}

Try / catch

if err != nil && err.Error() == "invalid channel-less operation" {
  // retry via a channel-scoped executor: ledger.GetQueryExecutorForChannel(channelID)
}

Prevention

When it happens

Trigger: Any GetState(key) call routed through DummyQueryExecutorShim — i.e., channel-less lifecycle code paths attempting to read ledger state, such as installing a non-_lifecycle chaincode in a channel-less context.

Common situations: Internal misuse of the lifecycle shim: calling chaincode that performs GetState without a channel context; installing/operating on a chaincode other than _lifecycle through channel-less APIs.

Related errors


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