geektutu/7days-golang · error

rpc: service already defined:

Error message

rpc: service already defined: 

What it means

Register (or RegisterByName via newService + LoadOrStore) detected that a service with the same name is already published in the server's serviceMap. The library forbids double registration to keep the method table unambiguous.

Source

Thrown at gee-rpc/day6-load-balance/server.go:223

		}
		go server.ServeConn(conn)
	}
}

// Accept accepts connections on the listener and serves requests
// for each incoming connection.
func Accept(lis net.Listener) { DefaultServer.Accept(lis) }

// Register publishes in the server the set of methods of the
// receiver value that satisfy the following conditions:
//	- exported method of exported type
//	- two arguments, both of exported type
//	- the second argument is a pointer
//	- one return value, of type error
func (server *Server) Register(rcvr interface{}) error {
	s := newService(rcvr)
	if _, dup := server.serviceMap.LoadOrStore(s.name, s); dup {
		return errors.New("rpc: service already defined: " + s.name)
	}
	return nil
}

// Register publishes the receiver's methods in the DefaultServer.
func Register(rcvr interface{}) error { return DefaultServer.Register(rcvr) }

const (
	connected        = "200 Connected to Gee RPC"
	defaultRPCPath   = "/_geeprc_"
	defaultDebugPath = "/debug/geerpc"
)

// ServeHTTP implements an http.Handler that answers RPC requests.
func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.Method != "CONNECT" {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusMethodNotAllowed)

View on GitHub (pinned to cf36443821)

Solutions

  1. Remove the duplicate Register call; register each service once during server setup.
  2. If a different type shares the Go name, alias one of them or register only one receiver per name.
  3. Ignore the error deliberately if re-registration is expected and harmless, e.g. if err != nil && !strings.Contains(err.Error(), "already defined") { return err }.

Example fix

// before
_ = srv.Register(new(Foo))
_ = srv.Register(new(Foo)) // panics/errors here
// after
_ = srv.Register(new(Foo))
Defensive patterns

Strategy: try-catch

Validate before calling

// register each service exactly once, e.g. via a registration table
var registered = map[string]bool{}
func registerOnce(srv *geeRPC.Server, rcvr interface{}) error {
    name := reflect.TypeOf(rcvr).Elem().Name()
    if registered[name] { return nil }
    if err := srv.Register(rcvr); err != nil { return err }
    registered[name] = true
    return nil
}

Try / catch

if err := srv.Register(new(Foo)); err != nil && !strings.Contains(err.Error(), "already defined") { return err } // tolerate deliberate duplicates

Prevention

When it happens

Trigger: Calling server.Register(new(Foo)) twice for the same type name, or registering two different types whose reflected names collide (same type name in different packages both resolve to "Foo").

Common situations: Duplicated Register calls in initialization code paths (e.g. both main and an init function register the service), hot-reload code that re-registers handlers, or same-named structs in different packages.

Related errors


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