geektutu/7days-golang · error
rpc: service already defined:
Error message
rpc: service already defined:
What it means
Register publishes a receiver's methods in the server's serviceMap keyed by the service name derived from the receiver type. If a service with the same name is already registered, LoadOrStore reports a duplicate and Register returns this error rather than silently overwriting the existing registration.
Source
Thrown at gee-rpc/day4-timeout/server.go:222
}
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) }
View on GitHub (pinned to cf36443821)
Solutions
- Register each service only once per Server instance; guard initialization with sync.Once or an idempotency check
- Use a separate Server instance if you need independent registration lifecycles (e.g. per test)
- If the duplicate is intentional, ignore the returned error or check for it explicitly
- Rename one of the colliding receiver types so their reflected service names differ
Example fix
// before
srv.Register(new(Foo))
...
srv.Register(new(Foo)) // panics-free but errors: already defined
// after
var registerOnce sync.Once
registerOnce.Do(func() { _ = srv.Register(new(Foo)) }) Defensive patterns
Strategy: try-catch
Validate before calling
// guard against double registration
if _, loaded := srvServiceNames.LoadOrStore("Foo", true); loaded {
// skip duplicate Register call
} else {
_ = srv.Register(new(Foo))
} Try / catch
if err := srv.Register(new(Foo)); err != nil {
if strings.Contains(err.Error(), "rpc: service already defined") {
log.Println("Foo already registered; ignoring")
} else {
return err
}
} Prevention
- Register services exactly once, e.g. inside sync.Once or main init only
- Do not re-run registration logic on config reload without recreating the Server
- Use unique receiver type names to avoid reflected-name collisions
- Treat duplicate-registration errors as bugs and alert on them in tests
When it happens
Trigger: Calling server.Register(new(Foo)) twice on the same Server, or registering two different types whose reflected service name collides (e.g. same type name in different packages).
Common situations: Initialization code that may run twice on restart/reload; registering the same service on both DefaultServer and a custom server by mistake; test suites re-registering services across test cases without a fresh Server.
Related errors
- rpc: service already defined:
- rpc server: service/method request ill-formed:
- rpc server: can't find service
- rpc server: can't find method
- rpc: service already defined:
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/502c8c0dbb63a76f.
Report an issue: GitHub.