snail007/goproxy · warning

client control conn not exists

Error message

client control conn not exists

What it means

The bridge periodically writes a signal byte to each client's control connection. This error is produced when a BridgeItem exists but its ClientControl connection pointer is nil, meaning the client's control channel was never established or was already closed, so the signal cannot be sent and the item is cleaned up and retried.

Source

Thrown at services/tunnel_bridge.go:155

	return
}
func (s *TunnelBridge) ChnDeamon(item *BridgeItem) {
	go func() {
		log.Printf("%s conn chan deamon started", item.Key)
		for {
			var clientConn *net.Conn
			var serverConn *net.Conn
			serverConn = <-item.ServerChn
			log.Printf("%s server conn picked up", item.Key)
		OUT:
			for {
				_item, _ := s.br.Get(item.Key)
				Item := _item.(*BridgeItem)
				var err error
				if Item.ClientControl != nil && *Item.ClientControl != nil {
					_, err = (*Item.ClientControl).Write([]byte{'0'})
				} else {
					err = fmt.Errorf("client control conn not exists")
				}
				if err != nil {
					log.Printf("%s client control conn write signal fail, err: %s, retrying...", item.Key, err)
					utils.CloseConn(Item.ClientControl)
					*Item.ClientControl = nil
					Item.ClientControl = nil
					time.Sleep(time.Second * 3)
					continue
				} else {
					select {
					case clientConn = <-item.ClientChn:
						log.Printf("%s client conn picked up", item.Key)
						break OUT
					case <-time.After(time.Second * time.Duration(*s.cfg.Timeout*5)):
						log.Printf("%s client conn picked timeout, retrying...", item.Key)
					}
				}
			}

View on GitHub (pinned to e6d6a821db)

Solutions

  1. Restart/reconnect the client so it re-establishes its control connection
  2. Check client-to-server connectivity and keep-alive settings so the control connection is not idle-killed by firewalls/NAT
  3. Verify the client is running a compatible version and its control port/key config matches the server
  4. Inspect server logs just before this error to find why the control conn was closed and address that root cause
Defensive patterns

Strategy: retry

Validate before calling

// before relying on a bridge, verify the client control channel is registered:
item, ok := bridge.Get(key)
if !ok || item.ClientControl == nil || *item.ClientControl == nil {
    // wait/retry for the client to (re)register instead of signaling
    time.Sleep(time.Second)
}

Try / catch

// server-side is a log+retry loop; on the client, wrap reconnects:
for {
    err := client.ConnectAndServe()
    if err != nil {
        log.Printf("control conn lost: %v; reconnecting in 3s", err)
        time.Sleep(3 * time.Second)
        continue
    }
    break
}

Prevention

When it happens

Trigger: During the bridge scan loop, Item.ClientControl is nil (or points to a nil conn) when the code tries to Write the '0' signal; typically after the client disconnected, before registration completed, or after a previous failure nil-ed the pointer.

Common situations: Client behind flaky NAT/network dropped its control connection; client crashed or was restarted while server-side bridge item lingered; firewall idle-timeout killed the long-lived control connection; client never finished connecting due to wrong key/address.

Related errors


AI-assisted analysis of snail007/goproxy@e6d6a821db (2026-09-03). Data as JSON: /api/errors/14be50d2f7f26ef3. Report an issue: GitHub.