charmbracelet/crush · error

server error: %v

Error message

server error: %v

What it means

The `server` command runs an HTTP server and watches an error channel. When any goroutine pushes a non-nil error that is not http.ErrServerClosed, the command closes the server and returns this wrapped error, causing the CLI to exit non-zero. It is the top-level propagation point for any runtime failure inside the server loop.

Source

Thrown at internal/cmd/server.go:79

		errch := make(chan error, 1)
		sigch := make(chan os.Signal, 1)
		sigs := []os.Signal{os.Interrupt}
		sigs = append(sigs, addSignals(sigs)...)
		signal.Notify(sigch, sigs...)

		go func() {
			errch <- srv.ListenAndServe()
		}()

		select {
		case <-sigch:
			slog.Info("Received interrupt signal...")
		case err = <-errch:
			if err != nil && !errors.Is(err, server.ErrServerClosed) {
				_ = srv.Close()
				slog.Error("Server error", "error", err)
				return fmt.Errorf("server error: %v", err)
			}
		}

		if errors.Is(err, server.ErrServerClosed) {
			return nil
		}

		ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second)
		defer cancel()

		slog.Info("Shutting down...")

		if err := srv.Shutdown(ctx); err != nil {
			slog.Error("Failed to shutdown server", "error", err)
			return fmt.Errorf("failed to shutdown server: %v", err)
		}

		return nil

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check that the configured listen address/port is free (lsof -i :PORT or ss -ltnp) and stop the conflicting process or change the port
  2. Run the command with sufficient privileges or use a port >=1024 if binding a privileged port
  3. Inspect the 'Server error' slog line printed just before this error for the root cause
  4. If shutting down intentionally, ensure only ErrServerClosed is sent or filtered correctly

Example fix

// before
return fmt.Errorf("server error: %v", err)
// after
return fmt.Errorf("server error: %w", err) // preserve wrap for errors.Is checks downstream
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting the server
if l, err := net.Listen("tcp", addr); err != nil {
    return fmt.Errorf("address %s unavailable: %w", addr, err)
} else {
    l.Close()
}

Try / catch

if err := runServer(ctx); err != nil {
    if errors.Is(err, server.ErrServerClosed) {
        return nil // intentional shutdown
    }
    slog.Error("Server failed", "error", err)
    os.Exit(1)
}

Prevention

When it happens

Trigger: Any error sent on errch (e.g. http.Server Serve/ListenAndServe failing: port already in use, permission denied on socket, TLS cert issues) that is not server.ErrServerClosed.

Common situations: Port 8080 (or configured port) already bound by another process; running without privileges on a low port; interface/address misconfiguration; TLS certificate files missing or invalid.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/84a8a1ef13093717. Report an issue: GitHub.