{"record":{"id":"e61b27f154d69f63","repo":"sipeed/picoclaw","slug":"failed-to-connect-to-whatsapp-bridge-w","errorCode":null,"errorMessage":"failed to connect to WhatsApp bridge: %w","messagePattern":"failed to connect to WhatsApp bridge: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/channels/whatsapp/whatsapp.go","lineNumber":69,"sourceCode":"}\n\nfunc (c *WhatsAppChannel) Start(ctx context.Context) error {\n\tlogger.InfoCF(\"whatsapp\", \"Starting WhatsApp channel\", map[string]any{\n\t\t\"bridge_url\": c.url,\n\t})\n\n\tc.ctx, c.cancel = context.WithCancel(ctx)\n\n\tdialer := websocket.DefaultDialer\n\tdialer.HandshakeTimeout = 10 * time.Second\n\n\tconn, resp, err := dialer.Dial(c.url, nil)\n\tif resp != nil {\n\t\t_ = resp.Body.Close()\n\t}\n\tif err != nil {\n\t\tc.cancel()\n\t\treturn fmt.Errorf(\"failed to connect to WhatsApp bridge: %w\", err)\n\t}\n\n\tc.mu.Lock()\n\tc.conn = conn\n\tc.connected = true\n\tc.mu.Unlock()\n\n\tc.SetRunning(true)\n\tlogger.InfoC(\"whatsapp\", \"WhatsApp channel connected\")\n\n\tgo c.listen()\n\n\treturn nil\n}\n\nfunc (c *WhatsAppChannel) Stop(ctx context.Context) error {\n\tlogger.InfoC(\"whatsapp\", \"Stopping WhatsApp channel...\")\n","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/whatsapp/whatsapp.go#L51-L87","documentation":"Returned by WhatsAppChannel.Start when gorilla/websocket's Dialer.Dial fails to establish a connection to the configured bridge URL (cfg.BridgeURL). The %w chain preserves the underlying error, commonly websocket.ErrBadHandshake when the server replies with a non-101 status. The channel's internal context is cancelled before returning, so the channel is left stopped.","triggerScenarios":"Start(ctx) calls dialer.Dial(c.url, nil) with a 10s handshake timeout: bridge process not running, wrong scheme (http:// instead of ws://), bridge listening on a different host/port, TLS failure on wss://, or reverse proxy not upgrading the connection.","commonSituations":"The WhatsApp bridge container/service (e.g. a whatsapp-web bridge) is down or was never started; BridgeURL in channel config points to the wrong port; an nginx/caddy front proxy lacks Upgrade/Connection headers for websocket; self-signed cert on wss:// rejected by default TLS config.","solutions":["Verify the bridge process is running and its port matches config.BridgeURL (e.g. ws://127.0.0.1:PORT).","Test reachability with a standalone websocket client or curl against the bridge's HTTP health endpoint.","If a reverse proxy fronts the bridge, add websocket upgrade headers (Upgrade/Connection) to that route.","For wss:// certificate failures, fix the cert chain or point to a properly signed cert.","Ensure the URL scheme is ws:// or wss://, not http:// or https://."],"exampleFix":"// before\nurl := \"http://127.0.0.1:8125\"  // wrong scheme\n// after\nurl := \"ws://127.0.0.1:8125\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(cfg.BridgeURL)\nif err != nil || (u.Scheme != \"ws\" && u.Scheme != \"wss\") {\n    return fmt.Errorf(\"bridge URL must be ws:// or wss://, got %q\", cfg.BridgeURL)\n}\nif _, err := net.DialTimeout(\"tcp\", u.Host, 3*time.Second); err != nil {\n    return fmt.Errorf(\"bridge unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := ch.Start(ctx); err != nil {\n    if strings.Contains(err.Error(), \"failed to connect to WhatsApp bridge\") {\n        // inspect errors.Unwrap chain for websocket.ErrBadHandshake => HTTP-level problem\n    }\n    return err\n}","preventionTips":["Pre-flight the bridge with a TCP dial or health endpoint before starting the channel.","Use supervision with backoff around Start so bridge outages self-heal.","Document the required ws:// scheme in channel config templates to prevent http:// typos."],"tags":["whatsapp","websocket","bridge","connection","startup"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}