jeessy2/ddns-go · critical

监听端口发生异常, 请检查端口是否被占用! %s

Error message

监听端口发生异常, 请检查端口是否被占用! %s

What it means

runWebServer binds the HTTP listener with net.Listen("tcp", *listen). If binding fails (port already in use, permission denied, invalid address), it returns this error telling the user to check whether the port is occupied. The underlying OS error is appended via %s.

Source

Thrown at main.go:211

	// 启动静态文件服务
	http.HandleFunc("/static/", web.AuthAssert(staticFsFunc))
	http.HandleFunc("/favicon.ico", web.AuthAssert(faviconFsFunc))
	http.HandleFunc("/login", web.AuthAssert(web.Login))
	http.HandleFunc("/loginFunc", web.AuthAssert(web.LoginFunc))

	http.HandleFunc("/", web.Auth(web.Writing))
	http.HandleFunc("/save", web.Auth(web.Save))
	http.HandleFunc("/setLang", web.Auth(web.SetLang))
	http.HandleFunc("/logs", web.Auth(web.Logs))
	http.HandleFunc("/clearLog", web.Auth(web.ClearLog))
	http.HandleFunc("/webhookTest", web.Auth(web.WebhookTest))
	http.HandleFunc("/logout", web.Auth(web.Logout))

	util.Log("监听 %s", *listen)

	l, err := net.Listen("tcp", *listen)
	if err != nil {
		return errors.New(util.LogStr("监听端口发生异常, 请检查端口是否被占用! %s", err))
	}

	return http.Serve(l, nil)
}

// 以守护/分离进程方式运行(Unix 使用 setsid,Windows 使用 DETACHED_PROCESS)
func runAsDaemon() error {
	exe, err := os.Executable()
	if err != nil {
		return err
	}

	// 过滤掉 -d 参数
	args := make([]string, 0, len(os.Args))
	args = append(args, exe)
	for i := 1; i < len(os.Args); i++ {
		if os.Args[i] == "-d" {
			continue

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Find and stop the process occupying the port: lsof -i :PORT or ss -tlnp, then kill it or change -listen to a free port
  2. Run with elevated privileges if binding a privileged port, or use a port >= 1024
  3. Check the -listen value for typos/invalid address syntax (e.g. ':8080' or '0.0.0.0:8080')
  4. Read the wrapped OS error after the '!' for the precise cause (address in use vs permission denied)

Example fix

// before
./app -listen :8080   # fails: port in use
// after
ss -tlnp | grep 8080  # find offender
./app -listen :8081   # or kill the offending process
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight check before starting the server
func portFree(addr string) bool {
  l, err := net.Listen("tcp", addr)
  if err != nil {
    return false
  }
  l.Close()
  return true
}

Type guard

null

Try / catch

l, err := net.Listen("tcp", *listen)
if err != nil {
  return errors.New(util.LogStr("监听端口发生异常, 请检查端口是否被占用! %s", err))
}
// caller:
if err := runWebServer(); err != nil {
  if strings.Contains(err.Error(), "监听端口发生异常") {
    // instruct user to free the port or change -listen
  }
}

Prevention

When it happens

Trigger: Starting the app with -listen pointing to a port already bound by another process; binding to a privileged port (<1024) without root; malformed listen address; IPv6 address not available on the host.

Common situations: Two instances of the app running simultaneously; another service (nginx, previous un-killed process) occupies the port; Docker/container lacks port binding permission; typo in the listen flag.

Related errors


AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03). Data as JSON: /api/errors/3702725fedfa60f6. Report an issue: GitHub.