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
- Remove the duplicate Register call; register each service once during server setup.
- If a different type shares the Go name, alias one of them or register only one receiver per name.
- 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
- Centralize all Register calls in one init function.
- Avoid registering in both package init() and main().
- Give receivers in different packages distinct type names or alias them.
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
- rpc: service already defined:
- rpc server: can't find service
- rpc: service already defined:
- rpc server: can't find service
- rpc: service already defined:
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/bf5b7710e58c6702.
Report an issue: GitHub.