{"record":{"id":"9ebc0d8237a8b64e","repo":"github/github-mcp-server","slug":"callback-server-w","errorCode":null,"errorMessage":"callback server: %w","messagePattern":"callback server: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/oauth/callback.go","lineNumber":72,"sourceCode":"\t}\n\treturn listener, nil\n}\n\n// newCallbackServer starts a callback server on listener that validates state\n// and reports the result on a buffered channel. The redirect URI always uses\n// localhost so it matches the value registered on the OAuth/GitHub App.\nfunc newCallbackServer(listener net.Listener, expectedState string) *callbackServer {\n\tcs := &callbackServer{\n\t\tserver:   &http.Server{ReadHeaderTimeout: 10 * time.Second}, // ReadHeaderTimeout guards against Slowloris.\n\t\tlistener: listener,\n\t\tredirect: fmt.Sprintf(\"http://localhost:%d/callback\", listener.Addr().(*net.TCPAddr).Port),\n\t\tresults:  make(chan callbackResult, 1),\n\t}\n\tcs.server.Handler = cs.handler(expectedState)\n\n\tgo func() {\n\t\tif err := cs.server.Serve(listener); err != nil && err != http.ErrServerClosed {\n\t\t\tcs.report(callbackResult{err: fmt.Errorf(\"callback server: %w\", err)})\n\t\t}\n\t}()\n\n\treturn cs\n}\n\n// handler renders the callback endpoint. It reports the outcome exactly once and\n// always shows the user a friendly page.\nfunc (cs *callbackServer) handler(expectedState string) http.Handler {\n\tmux := http.NewServeMux()\n\tmux.HandleFunc(\"/callback\", func(w http.ResponseWriter, r *http.Request) {\n\t\tq := r.URL.Query()\n\n\t\tif errCode := q.Get(\"error\"); errCode != \"\" {\n\t\t\tmsg := errCode\n\t\t\tif desc := q.Get(\"error_description\"); desc != \"\" {\n\t\t\t\tmsg = fmt.Sprintf(\"%s: %s\", errCode, desc)\n\t\t\t}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/internal/oauth/callback.go#L54-L90","documentation":"The callback HTTP server's Serve loop terminated with an error other than http.ErrServerClosed — reported through the same single-slot channel as real OAuth outcomes. Because the listener was successfully bound just before, this is an accept-loop failure: the listener died underneath the server (fd closed, socket torn down) or the accept syscall is persistently failing.","triggerScenarios":"cs.server.Serve(listener) at internal/oauth/callback.go:66 returns a non-ErrServerClosed error: another goroutine closed the listener's file descriptor, the OS invalidated the socket (VM suspend/resume, network namespace change), or accept hits EMFILE (process fd limit exhausted). The error is delivered to the flow via cs.report, so the user sees the flow abort with 'callback server: ...'.","commonSituations":"Container live-restore or checkpoint/restore tearing down sockets; ulimit -n exhausted by an fd leak elsewhere in the process; laptop suspend/resume during the OAuth wait; test harnesses closing the listener to simulate shutdown but the close races an in-flight accept.","solutions":["Check the wrapped accept error: 'too many open files' means an fd leak — raise the limit and fix the leak","If it follows a suspend/resume or container migration, simply restarting the OAuth flow recovers","Ensure only cs.close()/server.Shutdown is used to stop the callback server — never close the listener directly","Retry the login; the listener is re-bound on each new flow attempt"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// treat as flow failure surfaced via the flow's result channel;\n// check ulimit -n if the wrapped error is 'too many open files'\nif err != nil && strings.Contains(err.Error(), \"callback server:\") {\n    _ = ln.Close() // cleanup, then restart the login flow\n}","preventionTips":["Raise RLIMIT_NOFILE and fix fd leaks in long-running processes hosting the callback server","Only stop the server via Shutdown/ErrServerClosed paths, never by closing the listener"],"tags":["http-server","network","file-descriptors","rare","oauth"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}