geektutu/7days-golang · error
rpc: service already defined:
Error message
rpc: service already defined:
What it means
Register calls LoadOrStore on the server's serviceMap; if a service with the same derived name is already present, it returns this duplicate-registration error instead of overwriting the existing service. This protects against accidentally replacing method tables.
Source
Thrown at gee-rpc/day5-http-debug/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
- Ensure Register is called only once per service per Server instance (guard with sync.Once or init)
- Use a distinct exported type name for each service so the derived names don't collide
- Create a fresh Server for each test case instead of reusing one, or ignore the duplicate error intentionally if re-registration is expected
Example fix
// before
srv.Register(new(Foo))
srv.Register(new(Foo)) // duplicate
// after
var once sync.Once
func registerFoo(s *geeprc.Server) {
once.Do(func() { s.Register(new(Foo)) })
} Defensive patterns
Strategy: try-catch
Validate before calling
type Registrable interface{ ServiceName() string }
func alreadyRegistered(server *geeprc.Server, name string) bool {
seen, _ := registeredNames.Load(name) // track names in a sync.Map of your own
return seen != nil
} Try / catch
if err := srv.Register(new(Foo)); err != nil {
if strings.Contains(err.Error(), "service already defined") {
log.Printf("Foo already registered; skipping")
} else {
return err
}
} Prevention
- Register each service exactly once, e.g. in an init() or a sync.Once-guarded setup
- Give every RPC receiver a unique exported type name to avoid derived-name collisions
- In tests, build a fresh Server per test instead of reusing a global DefaultServer
- Centralize registration in one function so duplicates are easy to spot in review
When it happens
Trigger: Calling Register(new(Foo)) twice on the same Server, or registering two receivers whose type names are identical (e.g. two structs both named Foo in different packages).
Common situations: Test suites re-registering fixtures in setup code without a fresh Server, accidentally registering the same receiver on both DefaultServer and a custom Server reused across tests, or name collisions between same-named types.
Related errors
- rpc: service already defined:
- rpc: service already defined:
- rpc server: can't find service
- 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/67feca4de822b0e0.
Report an issue: GitHub.