chenhg5/cc-connect · critical

cloud_web: gateway listen: %w

Error message

cloud_web: gateway listen: %w

What it means

The cloud-web platform's gateway transport failed to bind its inbound webhook HTTP listener when Platform.Start() was called. The transport opens a TCP listener (default :8099) so the cloud-web bridge can POST events to it; if net.Listen fails the whole Start fails and the platform cannot start. The wrapped OS error tells you exactly why the bind failed.

Source

Thrown at platform/cloud-web/gateway.go:95

	t.caps = caps
	t.mu.Unlock()
}

func (t *gatewayTransport) Start(ctx context.Context, onInbound inboundHandler) error {
	t.onInbound = onInbound
	runCtx, cancel := context.WithCancel(ctx)
	t.cancel = cancel

	mux := http.NewServeMux()
	mux.HandleFunc(t.webhookPath, t.webhookHandler)
	t.server = &http.Server{
		Handler:           mux,
		ReadHeaderTimeout: 10 * time.Second,
	}
	ln, err := net.Listen("tcp", t.listen)
	if err != nil {
		cancel()
		return fmt.Errorf("cloud_web: gateway listen: %w", err)
	}
	t.listener = ln

	go func() {
		slog.Info("cloud_web: gateway webhook listening", "addr", ln.Addr().String(), "path", t.webhookPath)
		if err := t.server.Serve(ln); err != nil && err != http.ErrServerClosed {
			slog.Error("cloud_web: gateway server error", "error", err)
		}
	}()

	if t.registerURL != "" {
		caps, err := t.register(runCtx)
		if err != nil {
			slog.Warn("cloud_web: gateway register failed", "error", err)
		} else {
			t.setCaps(caps)
		}
	}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Find and stop the process holding the port (lsof -i :8099 or ss -ltnp), or kill the stale cc-connect instance.
  2. Change the listen value in the cloud-web platform section of config.toml to a free port (e.g. ":8100").
  3. If binding a privileged port, run as root, use CAP_NET_BIND_SERVICE, or put a reverse proxy in front.
  4. Verify the listen string syntax: '[host]:port', e.g. ':8099' or '127.0.0.1:8099'.

Example fix

// config.toml — before
[[platform]]
name = "cloud-web"
listen = ":8099"   # fails: address already in use

// after
[[platform]]
name = "cloud-web"
listen = ":8123"   # free port
Defensive patterns

Strategy: validation

Validate before calling

// before calling Start, check the port is free
conn, err := net.Listen("tcp", ":8099")
if err != nil {
    return fmt.Errorf("port :8099 unavailable: %w", err)
}
conn.Close() // close and let Start bind it

Try / catch

if err := platform.Start(ctx, handler); err != nil {
    var opErr *net.OpError
    if errors.As(err, &opErr) && errors.Is(opErr.Err, syscall.EADDRINUSE) {
        slog.Error("gateway port in use; stop the other instance or change listen", "error", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Start (e.g. via cc-connect startup) when the configured listen address is already in use by another process, the port is privileged (below 1024) without permissions, the address is invalid/unresolvable, or an instance of cc-connect is already running with the same listen setting.

Common situations: Duplicate cc-connect instance from a stale systemd/launchd service; another dev server squatting on :8099; listen set to ':80' or ':443' in config.toml; Docker container networking the port twice; typo like 'localhost::8099'.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/842cb7fb00607ea4. Report an issue: GitHub.