{"record":{"id":"e401c70c77cc360b","repo":"knadh/listmonk","slug":"error-requesting-subscription-url-v","errorCode":null,"errorMessage":"error requesting subscription URL: %v","messagePattern":"error requesting subscription URL: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/bounce/webhooks/ses.go","lineNumber":99,"sourceCode":"// by parsing and verifying the payload and calling the subscribe / unsubscribe URL.\nfunc (s *SES) ProcessSubscription(b []byte) error {\n\tvar n sesNotif\n\tif err := json.Unmarshal(b, &n); err != nil {\n\t\treturn fmt.Errorf(\"error unmarshalling SNS notification: %v\", err)\n\t}\n\tif err := s.verifyNotif(n); err != nil {\n\t\treturn err\n\t}\n\n\t// Make an HTTP request to the sub/unsub URL.\n\tu := n.SubscribeURL\n\tif n.Type == \"UnsubscriptionConfirmation\" {\n\t\tu = n.UnsubscribeURL\n\t}\n\n\tresp, err := http.Get(u)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error requesting subscription URL: %v\", err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"non 200 response on subscription URL: %v\", resp.StatusCode)\n\t}\n\n\treturn nil\n}\n\n// ProcessBounce processes an SES bounce notification and returns a Bounce object.\nfunc (s *SES) ProcessBounce(b []byte) (models.Bounce, error) {\n\tvar (\n\t\tbounce models.Bounce\n\t\tn      sesNotif\n\t)\n\tif err := json.Unmarshal(b, &n); err != nil {\n\t\treturn bounce, fmt.Errorf(\"error unmarshalling SES notification: %v\", err)\n\t}","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/knadh/listmonk/blob/670c01717d48647093335cc23a6be6f4b79c3b6b/internal/bounce/webhooks/ses.go#L81-L117","documentation":"After parsing and signature-verifying an SNS subscription (un)confirmation, ProcessSubscription must visit the SubscribeURL (or UnsubscribeURL) with HTTP GET to complete the confirmation. If the HTTP GET itself fails at the transport level (DNS, TLS, connection refused, timeout), the handler returns 'error requesting subscription URL'.","triggerScenarios":"http.Get(n.SubscribeURL or n.UnsubscribeURL) returns a non-nil error: no outbound internet/DNS on the server, egress firewall blocking sns.<region>.amazonaws.com, TLS interception, IPv6 issues, or a malformed/unreachable URL in a forged-but-signature-valid payload.","commonSituations":"listmonk deployed in a restricted network (Docker/K8s) without outbound internet access; corporate proxy required but not configured (HTTP_PROXY ignored by http.Get default transport); DNS resolution failures; SES in a region blocked by network policy.","solutions":["Verify the server can curl the SubscribeURL shown in the SNS console/notification directly","Open outbound HTTPS (443) egress to *.amazonaws.com from the listmonk host/container","If a proxy is required, configure it via HTTP_PROXY/HTTPS_PROXY env vars so the default transport honors it","Fix DNS resolution on the host (check resolv.conf, VPC DNS, or CoreDNS in Kubernetes)","Retry the subscription — SNS will re-send SubscriptionConfirmation notifications"],"exampleFix":"// before: run container with no egress\ndocker run --network internal listmonk\n// after: allow outbound 443 or use a proxy env\nHTTPS_PROXY=http://proxy.corp:3128 docker run listmonk","handlingStrategy":"retry","validationCode":"u := \"https://sns.<region>.amazonaws.com/?Action=ConfirmSubscription...\"\nhost, err := url.Parse(u)\nif err != nil { return false }\naddrs, err := net.LookupHost(host.Hostname())\nreturn err == nil && len(addrs) > 0\n// pre-flight: resolve the SubscribeURL host before processing","typeGuard":null,"tryCatchPattern":"err := handler.ProcessSubscription(body)\nif err != nil {\n    if strings.HasPrefix(err.Error(), \"error requesting subscription URL\") {\n        log.Printf(\"SNS confirmation URL unreachable, will rely on SNS retry: %v\", err)\n        // SNS re-sends confirmations; return 500 so retries/schedule re-check\n        http.Error(w, \"subscription URL unreachable\", http.StatusBadGateway)\n        return\n    }\n    http.Error(w, \"webhook error\", http.StatusInternalServerError)\n}","preventionTips":["Guarantee outbound HTTPS egress to *.amazonaws.com from the deployment","Configure HTTP(S)_PROXY env vars if the network requires a proxy","Monitor DNS health in containers/Kubernetes","Re-request the subscription after fixing connectivity; SNS will resend the confirmation"],"tags":["network","http","aws","sns","webhook"],"backgroundTag":"http-request-failed","analyzedSha":"670c01717d48647093335cc23a6be6f4b79c3b6b","analyzedAt":"2026-09-01T03:39:35.452Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}