unknwon/the-way-to-go_ZH_CN · error

"ListenAndServe: " + err.Error()

Error message

"ListenAndServe: " + err.Error()

What it means

Panic in the WebSocket echo server main (section 15.11): after registering http.Handle("/websocket", websocket.Handler(server)), a failure of http.ListenAndServe(":12345", nil) is escalated with panic("ListenAndServe: " + err.Error()). The panic text names whatever the net layer reported.

Source

Thrown at eBook/15.11.md:39

func server(ws *websocket.Conn) {
	fmt.Printf("new connection\n")
	buf := make([]byte, 100)
	for {
		if _, err := ws.Read(buf); err != nil {
			fmt.Printf("%s", err.Error())
			break
		}
	}
	fmt.Printf(" => closing connection\n")
	ws.Close()
}

func main() {
	http.Handle("/websocket", websocket.Handler(server))
	err := http.ListenAndServe(":12345", nil)
	if err != nil {
		panic("ListenAndServe: " + err.Error())
	}
}
```

示例 15.25 [websocket_client.go](examples/chapter_15/websocket_client.go)
```go
package main

import (
	"fmt"
	"time"
	"websocket"
)

func main() {
	ws, err := websocket.Dial("ws://localhost:12345/websocket", "",
		"http://localhost/")
	if err != nil {

View on GitHub (pinned to 7a54d34d36)

Solutions

  1. Free the port: find the holder (lsof -i :12345 or ss -ltnp) and stop it, or change the port in the code/flag
  2. Bind 127.0.0.1:12345 for local dev to avoid clashing with LAN-facing services
  3. Replace the panic with log.Fatal("ListenAndServe: ", err) for a clean, logged exit
  4. Ensure prior instances shut down gracefully so the socket is released before restart

Example fix

// before
err := http.ListenAndServe(":12345", nil)
if err != nil {
    panic("ListenAndServe: " + err.Error())
}

// after
if err := http.ListenAndServe("127.0.0.1:12345", nil); err != nil {
    log.Fatal("ListenAndServe: ", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// claim the port first; if this fails you get a clear reason, not a panic
func portAvailable(addr string) bool {
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return false
    }
    ln.Close()
    return true
}

if !portAvailable(":12345") {
    log.Fatal(":12345 already in use — stop the other instance or change the port")
}

Try / catch

// if you keep the panic, at least exit cleanly from it
defer func() {
    if r := recover(); r != nil {
        log.Fatal("server aborted:", r)
    }
}()
err := http.ListenAndServe(":12345", nil)

Prevention

When it happens

Trigger: ListenAndServe returns a non-nil error — most commonly 'listen tcp :12345: bind: address already in use' because another instance or process owns the port, or 'permission denied' when binding a privileged port without root.

Common situations: Running the server twice during development; a previous crashed instance still holding the socket; port 12345 occupied by an unrelated service; deploying to an environment where the port was not exposed/allocated.

Related errors


AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15). Data as JSON: /api/errors/9a0ff4055b2721d0. Report an issue: GitHub.