geektutu/7days-golang · error
rpc: service already defined:
Error message
rpc: service already defined:
What it means
Server.Register stores the receiver by its derived name in serviceMap using LoadOrStore; if a service with that name is already registered it returns this error instead of overwriting. Duplicate registration is refused to keep one canonical implementation per service name.
Source
Thrown at gee-rpc/day7-registry/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
- Call Register only once per service per Server instance (e.g. at startup/init)
- Guard registration with sync.Once or check whether the service is already registered
- Register a single instance and reuse it instead of re-registering per connection
- If you genuinely need a new implementation, create a new Server or use a distinct type name
Example fix
// before
func onConn(s *geerpc.Server) { s.Register(new(Foo)) } // called per connection
// after
var once sync.Once
func setup(s *geerpc.Server) { once.Do(func() { s.Register(new(Foo)) }) } Defensive patterns
Strategy: try-catch
Validate before calling
// register once per process
var registerOnce sync.Once
func ensureRegistered(s *geerpc.Server) {
registerOnce.Do(func() {
if err := s.Register(new(Foo)); err != nil {
if strings.Contains(err.Error(), "already defined") { return } // idempotent
log.Fatal(err)
}
})
} Try / catch
if err := srv.Register(new(Foo)); err != nil {
if strings.Contains(err.Error(), "already defined") {
return nil // treat as idempotent success
}
return err
} Prevention
- Register services only once, at startup, not per connection/request
- Do not register both a value and a pointer of the same type
- Treat duplicate registration as an idempotent no-op in setup code
When it happens
Trigger: Calling Register twice with the same receiver type (or two types whose derived name collides, e.g. value and pointer of the same type) on the same Server, or registering in code that runs on each reconnect/restart within the same process.
Common situations: Registration placed in a hot path or init function invoked multiple times; registering both Foo and *Foo; tests constructing one server but calling Register in setup run repeatedly.
Related errors
- rpc: service already defined:
- rpc: service already defined:
- rpc client: call failed:
- number of options is more than 1
- rpc server: service/method request ill-formed:
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/633ee2a6657c05f8.
Report an issue: GitHub.