{"record":{"id":"b27af130be2ba160","repo":"ipfs/kubo","slug":"failed-to-start-server-process-closing","errorCode":null,"errorMessage":"failed to start server, process closing","messagePattern":"failed to start server, process closing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/corehttp/corehttp.go","lineNumber":113,"sourceCode":"//\n// Passing nil for ready is equivalent to calling Serve().\nfunc ServeWithReady(node *core.IpfsNode, lis net.Listener, ready chan<- struct{}, options ...ServeOption) error {\n\t// make sure we close this no matter what.\n\tdefer lis.Close()\n\n\thandler, err := MakeHandler(node, lis, options...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\taddr, err := manet.FromNetAddr(lis.Addr())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tselect {\n\tcase <-node.Context().Done():\n\t\treturn fmt.Errorf(\"failed to start server, process closing\")\n\tdefault:\n\t}\n\n\tserver := &http.Server{\n\t\tHandler: handler,\n\t}\n\n\tvar serverError error\n\tserverClosed := make(chan struct{})\n\tgo func() {\n\t\tif ready != nil {\n\t\t\tclose(ready)\n\t\t}\n\t\tserverError = server.Serve(lis)\n\t\tclose(serverClosed)\n\t}()\n\n\t// wait for server to exit.","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/core/corehttp/corehttp.go#L95-L131","documentation":"ServeWithReady checks the node's context before constructing and starting the HTTP server (RPC API or gateway). If the node's context is already cancelled at startup time, kubo aborts with this error instead of launching a server on a dead node. It is a lifecycle guard: the process is closing, so serving traffic would be pointless.","triggerScenarios":"Calling ServeWithReady (directly or via Serve) with an IpfsNode whose Context() is already cancelled — e.g. the daemon received SIGINT/SIGTERM, `ipfs shutdown` was invoked, or the caller passed an already-cancelled context that the node context inherits, all while the HTTP server option chain is still being assembled.","commonSituations":"Daemon shutdown racing with gateway/API server startup; supervisory scripts that restart the daemon while an old process is still tearing down; programmatic kubo-as-a-library users whose node context expires before HTTP listeners start; slow initialization (large repo, migrations) combined with an external timeout cancelling the context.","solutions":["Wait for the previous daemon process to fully exit (or `ipfs shutdown`) before starting a new one that serves HTTP.","Check the node lifecycle before calling Serve/ServeWithReady; ensure the context passed into node construction is not already cancelled or near its deadline.","If using kubo as a library, use context.WithCancel without a short deadline for long-running nodes and only cancel on intentional shutdown.","Retry startup with backoff if this occurred during an automated restart race; the error is terminal for that attempt but the next attempt after teardown succeeds."],"exampleFix":"// before: starts server even while shutting down\nnode, err := core.NewNode(ctx, cfg)\ngo httpServe(node)\ncancel() // node context dies mid-startup\n\n// after: ensure context outlives the server\nnode, err := core.NewNode(context.Background(), cfg)\nif err != nil { return err }\ngo httpServe(node) // cancel only on shutdown, after servers exit","handlingStrategy":"retry","validationCode":"select {\ncase <-node.Context().Done():\n    // do not attempt to start the HTTP server\n    return node.Context().Err()\ndefault:\n    // safe to call Serve/ServeWithReady\n}","typeGuard":null,"tryCatchPattern":"err := corehttp.ServeWithReady(node, listener, opts)\nif err != nil {\n    if strings.Contains(err.Error(), \"process closing\") || errors.Is(node.Context().Err(), context.Canceled) {\n        // shutdown race: tear down and retry after the node exits\n        return retryAfterTeardown()\n    }\n    return err\n}","preventionTips":["Always check node.Context().Err() before starting HTTP servers on an embedded node.","Use context.WithCancel (no short deadline) for long-running daemon node contexts.","Serialize shutdown and startup: wait for the previous process to exit fully (pid check or lock) before relaunching.","Add retry-with-backoff around daemon startup in supervisor scripts."],"tags":["http-server","lifecycle","shutdown","context-canceled"],"backgroundTag":"context-canceled","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}