router-for-me/CLIProxyAPI · error
port %d is already in use
Error message
port %d is already in use
What it means
The Codex OAuth callback server (mirrors the Claude one) refuses to start because its configured callback port is already bound. The pre-start isPortAvailable probe failed, so the login flow aborts before opening the browser. Distinct from the async failure (error 199), which happens after the probe passes.
Source
Thrown at internal/auth/codex/oauth_server.go:79
}
// Start starts the OAuth callback server.
// It sets up the HTTP handlers for the callback and success endpoints,
// and begins listening on the specified port.
//
// Returns:
// - error: An error if the server fails to start
func (s *OAuthServer) Start() error {
s.mu.Lock()
defer s.mu.Unlock()
if s.running {
return fmt.Errorf("server is already running")
}
// Check if port is available
if !s.isPortAvailable() {
return fmt.Errorf("port %d is already in use", s.port)
}
mux := http.NewServeMux()
mux.HandleFunc("/auth/callback", s.handleCallback)
mux.HandleFunc("/success", s.handleSuccess)
s.server = &http.Server{
Addr: fmt.Sprintf(":%d", s.port),
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
s.running = true
// Start server in goroutine
go func() {
if err := s.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {View on GitHub (pinned to 78f0c4079e)
Solutions
- Identify and stop the holder: `lsof -i :<port>` / `ss -ltnp`, kill the stale process.
- Avoid concurrent logins; wait for the first to finish.
- Retry login with a different --oauth-callback-port.
- Move the callback port away from ports your other services use.
Example fix
# before ./cli-proxy-api login --provider codex # port held by stale process # after kill $(lsof -t -i :1455) ./cli-proxy-api login --provider codex
Defensive patterns
Strategy: validation
Validate before calling
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil { return fmt.Errorf("codex callback port %d busy; pass --oauth-callback-port", port) }
ln.Close() Try / catch
if err := server.Start(); err != nil && strings.Contains(err.Error(), "already in use") {
port = pickFreePort(); rebuildServer(port)
} Prevention
- Free the callback port or use a unique one per login attempt.
- Kill stale processes from previous logins before starting a new one.
When it happens
Trigger: Running Codex login while another CLIProxyAPI instance, a previous crashed process, or an unrelated service holds the callback port; two concurrent logins sharing the default port.
Common situations: Stale background process from an earlier login still bound; parallel logins from two terminals; the callback port colliding with a commonly used dev port; leftover container holding the port in CI.
Related errors
- port_in_use
- server failed to start: %w
- server failed to start: %w
- timeout waiting for OAuth callback
- failed to create token request: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/ba607db47859ba3c.
Report an issue: GitHub.