{"record":{"id":"cec0eb2819299d25","repo":"livekit/livekit","slug":"already-running","errorCode":null,"errorMessage":"already running","messagePattern":"already running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/server.go","lineNumber":216,"sourceCode":"\n\treturn\n}\n\nfunc (s *LivekitServer) Node() *livekit.Node {\n\treturn s.currentNode.Clone()\n}\n\nfunc (s *LivekitServer) HTTPPort() int {\n\treturn int(s.config.Port)\n}\n\nfunc (s *LivekitServer) IsRunning() bool {\n\treturn s.running.Load()\n}\n\nfunc (s *LivekitServer) Start() error {\n\tif s.running.Load() {\n\t\treturn errors.New(\"already running\")\n\t}\n\ts.doneChan = make(chan struct{})\n\n\tif err := s.router.RegisterNode(); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif err := s.router.UnregisterNode(); err != nil {\n\t\t\tlogger.Errorw(\"could not unregister node\", err)\n\t\t}\n\t}()\n\n\tif err := s.router.Start(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := s.ioService.Start(); err != nil {\n\t\treturn err","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/livekit/livekit/blob/ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6/pkg/service/server.go#L198-L234","documentation":"LivekitServer.Start is called on a server whose atomic running flag is already true. Start is not idempotent: it guards with s.running.Load() and returns this error instead of registering the node or spawning loops a second time.","triggerScenarios":"Calling Start() twice on the same *LivekitServer instance without waiting for it to shut down (doneChan closed / Stop called). Seen in tests (setupMultiNodeTestWithConfig) or when a supervisor restarts the start routine without recreating the server.","commonSituations":"Calling Start from both a main goroutine and an init helper; retrying Start after a transient failure elsewhere while the server actually came up; test scaffolding reusing a server object across cases.","solutions":["Check server.IsRunning() before calling Start","Create a new LivekitServer instance instead of re-Starting the existing one","Ensure only one goroutine calls Start (single supervisor path)"],"exampleFix":"// before\nserver.Start()\n// after\nif !server.IsRunning() {\n    if err := server.Start(); err != nil {\n        log.Fatal(err)\n    }\n}","handlingStrategy":"type-guard","validationCode":"if server.IsRunning() {\n    return nil // already started\n}\nerr := server.Start()","typeGuard":"func canStart(s *LivekitServer) bool { return !s.IsRunning() }","tryCatchPattern":null,"preventionTips":["Make Start single-flight (one goroutine owns the lifecycle)","Recreate the server instance for restarts instead of calling Start again","Use IsRunning() as a precondition in wrappers around Start"],"tags":["lifecycle","server","double-start"],"backgroundTag":"server-already-started","analyzedSha":"ee45c3f0b1a83bf4352dbccb6607ebf70b2a5de6","analyzedAt":"2026-09-02T03:56:08.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}