geektutu/7days-golang · error

RegisterPeerPicker called more than once

Error message

RegisterPeerPicker called more than once

What it means

Group.RegisterPeers panics if called more than once on the same Group. The peers (PeerPicker) is designed to be set exactly once at startup; re-registering would silently replace the peer selection strategy and break in-flight loads. This is a misuse guard against double initialization.

Source

Thrown at gee-cache/day7-proto-buf/geecache/geecache.go:83

// Get value for a key from cache
func (g *Group) Get(key string) (ByteView, error) {
	if key == "" {
		return ByteView{}, fmt.Errorf("key is required")
	}

	if v, ok := g.mainCache.get(key); ok {
		log.Println("[GeeCache] hit")
		return v, nil
	}

	return g.load(key)
}

// RegisterPeers registers a PeerPicker for choosing remote peer
func (g *Group) RegisterPeers(peers PeerPicker) {
	if g.peers != nil {
		panic("RegisterPeerPicker called more than once")
	}
	g.peers = peers
}

func (g *Group) load(key string) (value ByteView, err error) {
	// each key is only fetched once (either locally or remotely)
	// regardless of the number of concurrent callers.
	viewi, err := g.loader.Do(key, func() (interface{}, error) {
		if g.peers != nil {
			if peer, ok := g.peers.PickPeer(key); ok {
				if value, err = g.getFromPeer(peer, key); err == nil {
					return value, nil
				}
				log.Println("[GeeCache] Failed to get from peer", err)
			}
		}

		return g.getLocally(key)

View on GitHub (pinned to cf36443821)

Solutions

  1. Call RegisterPeers exactly once per Group, at initialization time
  2. If peer configuration changed, create a new Group instead of re-registering
  3. Guard the call site with an 'if g.Peers() == nil' style check or a sync.Once
  4. Restructure tests so each Group is used by only one RegisterPeers call

Example fix

// before
g.RegisterPeers(peers)
// ... later ...
g.RegisterPeers(newPeers) // panics
// after
if g.Peers() == nil {
    g.RegisterPeers(newPeers)
} else {
    g = geecache.NewGroup("scores", 2<<20, getter)
    g.RegisterPeers(newPeers)
}
Defensive patterns

Strategy: validation

Validate before calling

if g.Peers() == nil {
    g.RegisterPeers(peers)
}

Try / catch

// Go panics cannot be caught by try/catch; guard at call site or recover:
func safeRegister(g *geecache.Group, peers geecache.PeerPicker) (ok bool) {
    defer func() { if recover() != nil { ok = false } }()
    g.RegisterPeers(peers)
    return true
}

Prevention

When it happens

Trigger: Calling g.RegisterPeers(peers) a second time on a Group that already has peers registered, typically during re-configuration, hot-reload, or calling RegisterPeers in both setup code and a test helper.

Common situations: Test setups that build servers twice in one process; restarting the peer server without recreating the Group; accidentally calling RegisterPeers inside a loop or per-request path.

Related errors


AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03). Data as JSON: /api/errors/a49af665bd16bcad. Report an issue: GitHub.