{"record":{"id":"1be9d23eda546e4d","repo":"sipeed/picoclaw","slug":"whatsapp-connection-not-established-w-1be9d2","errorCode":null,"errorMessage":"whatsapp connection not established: %w","messagePattern":"whatsapp connection not established: %w","errorType":"exception","errorClass":"channels.ErrTemporary","httpStatus":null,"severity":"warning","filePath":"pkg/channels/whatsapp_native/whatsapp_native.go","lineNumber":425,"sourceCode":"\tc.HandleInboundContext(c.runCtx, chatID, content, mediaPaths, inboundCtx, sender)\n}\n\nfunc (c *WhatsAppNativeChannel) Send(ctx context.Context, msg bus.OutboundMessage) ([]string, error) {\n\tif !c.IsRunning() {\n\t\treturn nil, channels.ErrNotRunning\n\t}\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\tdefault:\n\t}\n\n\tc.mu.Lock()\n\tclient := c.client\n\tc.mu.Unlock()\n\n\tif client == nil || !client.IsConnected() {\n\t\treturn nil, fmt.Errorf(\"whatsapp connection not established: %w\", channels.ErrTemporary)\n\t}\n\n\t// Detect unpaired state: the client is connected (to WhatsApp servers)\n\t// but has not completed QR-login yet, so sending would fail.\n\tif client.Store.ID == nil {\n\t\treturn nil, fmt.Errorf(\"whatsapp not yet paired (QR login pending): %w\", channels.ErrTemporary)\n\t}\n\n\tto, err := parseJID(msg.ChatID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid chat id %q: %w\", msg.ChatID, err)\n\t}\n\n\twaMsg := &waE2E.Message{\n\t\tConversation: proto.String(msg.Content),\n\t}\n\n\tif _, err = client.SendMessage(ctx, to, waMsg); err != nil {","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/whatsapp_native/whatsapp_native.go#L407-L443","documentation":"Returned by WhatsAppNativeChannel.Send when the whatsmeow client is nil (channel not started) or client.IsConnected() is false (socket dropped). It wraps channels.ErrTemporary, so the channel manager schedules an exponential-backoff retry instead of dead-lettering the message.","triggerScenarios":"Send() invoked before Start completes, after Stop, or while whatsmeow is disconnected - e.g. the websocket dropped due to network loss and the event handler's reconnect logic has not yet re-established IsConnected().","commonSituations":"Outbound message queued while the WhatsApp session is down; transient internet outage on the host; the device re-connecting after sleep; sends racing a restart.","solutions":["Check the channel's running/connected state before sending, or rely on the manager's retry.","Restore network connectivity; whatsmeow reconnect paths will flip IsConnected() true again.","Inspect logs for preceding disconnect events to learn why the socket dropped.","If permanent (channel intentionally stopped), pause the channel config so queued sends stop."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if !ch.IsRunning() {\n    return errors.New(\"whatsapp native channel not running\")\n}","typeGuard":"func isTemporary(err error) bool { return errors.Is(err, channels.ErrTemporary) }","tryCatchPattern":"if _, err := ch.Send(ctx, msg); err != nil {\n    if errors.Is(err, channels.ErrTemporary) {\n        // not connected yet: backoff; whatsmeow reconnect or Start will restore\n    }\n}","preventionTips":["Check IsRunning() before enqueueing sends.","Monitor disconnect/reconnect events to anticipate send failures.","Let manager backoff handle transient disconnect windows rather than failing fast."],"tags":["whatsapp","whatsmeow","send","transient","reconnect"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}