canopy-network/canopy · error · ErrStoreGet

reverse iterator not supported on subtree store

Error message

reverse iterator not supported on subtree store

What it means

Raised unconditionally by subtreeStore.ReIterator for the same reason as Iterator: the subtree store is a pending-writes overlay with no reverse (descending-key) scan capability. Reverse iteration is intentionally unsupported rather than silently incorrect.

Solutions

  1. Perform reverse iteration on the underlying versioned store instead of the subtree overlay.
  2. Collect written keys in a list and sort descending if reverse traversal of pending ops is required.
  3. Restrict subtreeStore usage to Get/Set/Delete point operations.
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at store/txn.go:370 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06). Data as JSON: /api/errors/899aa25898821ae4. Report an issue: GitHub.

Appendix: source

Thrown at store/txn.go:370

	s.l.Lock()
	s.ops[lib.MemHash(key)] = valueOp{key: key, value: value, version: s.version, op: opSet}
	s.l.Unlock()
	return nil
}

func (s *subtreeStore) Delete(key []byte) lib.ErrorI {
	s.l.Lock()
	s.ops[lib.MemHash(key)] = valueOp{key: key, version: s.version, op: opDelete}
	s.l.Unlock()
	return nil
}

func (s *subtreeStore) Iterator([]byte) (lib.IteratorI, lib.ErrorI) {
	return nil, ErrStoreGet(fmt.Errorf("iterator not supported on subtree store"))
}

func (s *subtreeStore) RevIterator([]byte) (lib.IteratorI, lib.ErrorI) {
	return nil, ErrStoreGet(fmt.Errorf("reverse iterator not supported on subtree store"))
}

// Copy creates a new Txn with the same configuration and txn as the original
func (t *Txn) Copy(reader TxnReaderI, writer TxnWriterI) *Txn {
	return &Txn{
		reader:       reader,
		writer:       writer,
		prefix:       t.prefix,
		state:        t.state,
		sort:         t.sort,
		writeVersion: t.writeVersion,
		txn:          t.txn.copy(),
	}
}

// txn() returns a copy of the current transaction txn
func (t *txn) copy() *txn {
	t.l.Lock()

View on GitHub (pinned to ee8197d91d)