{"record":{"id":"0002056a2f31e8ca","repo":"sipeed/picoclaw","slug":"whatsapp-send-w-000205","errorCode":null,"errorMessage":"whatsapp send: %w","messagePattern":"whatsapp send: %w","errorType":"exception","errorClass":"channels.ErrTemporary","httpStatus":null,"severity":"error","filePath":"pkg/channels/whatsapp_native/whatsapp_native.go","lineNumber":444,"sourceCode":"\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 {\n\t\treturn nil, fmt.Errorf(\"whatsapp send: %w\", channels.ErrTemporary)\n\t}\n\treturn nil, nil\n}\n\n// parseJID converts a chat ID (phone number or JID string) to types.JID.\nfunc parseJID(s string) (types.JID, error) {\n\ts = strings.TrimSpace(s)\n\tif s == \"\" {\n\t\treturn types.JID{}, fmt.Errorf(\"empty chat id\")\n\t}\n\tif strings.Contains(s, \"@\") {\n\t\treturn types.ParseJID(s)\n\t}\n\treturn types.NewJID(s, types.DefaultUserServer), nil\n}\n","sourceCodeStart":426,"sourceCodeEnd":460,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/whatsapp_native/whatsapp_native.go#L426-L460","documentation":"Returned by WhatsAppNativeChannel.Send when whatsmeow's client.SendMessage(ctx, to, waMsg) fails - the message was handed to the WhatsApp protocol stack and the server/link rejected or dropped it. The specific whatsmeow error is discarded and channels.ErrTemporary is wrapped, so the manager retries with backoff. Causes range from network drops mid-send to pairing/session-key problems and server-side rejections.","triggerScenarios":"Send() on a connected+paired client where SendMessage errors: socket drops between the IsConnected check and the write, session keys out of sync after phone-side logout, recipient JID not registered on WhatsApp, or WhatsApp server rejecting the payload.","commonSituations":"User unlinked the device from the phone (session invalid but socket briefly still up); phone offline for extended period causing key issues; sending to numbers that never had WhatsApp; transient server errors.","solutions":["Check recent logs for disconnect/pairing events - if the device was logged out, delete the store, restart, and re-scan QR.","Verify the recipient number actually has a WhatsApp account (test from the phone app).","If errors cluster with network instability, wait for reconnect; backoff retry will resend.","For permanent-looking rejections (e.g. banned number), stop retrying by moving the message to a dead-letter path."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if !ch.IsRunning() { return errors.New(\"channel not running\") }\n// Pairing/connect gates are internal; ensure no recent 'logged out' events before sending","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        // backoff retry; if repeated, suspect session invalidation -> re-pair\n    }\n}","preventionTips":["Do not unlink the device from the phone while the channel is in use.","Cap retries for messages whose recipient may not be on WhatsApp.","Watch for repeat ErrTemporary on the same chat id as a signal of a permanent recipient problem."],"tags":["whatsapp","whatsmeow","send","transient","session"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}