{"record":{"id":"4fecd902a778964c","repo":"knadh/listmonk","slug":"non-200-response-on-subscription-url-v","errorCode":null,"errorMessage":"non 200 response on subscription URL: %v","messagePattern":"non 200 response on subscription URL: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/bounce/webhooks/ses.go","lineNumber":103,"sourceCode":"\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}\n\tif err := s.verifyNotif(n); err != nil {\n\t\treturn bounce, err\n\t}\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/knadh/listmonk/blob/670c01717d48647093335cc23a6be6f4b79c3b6b/internal/bounce/webhooks/ses.go#L85-L121","documentation":"After successfully GETting the SNS SubscribeURL/UnsubscribeURL, ProcessSubscription requires HTTP 200. Any other status code returns 'non 200 response on subscription URL', meaning SNS's confirmation endpoint responded but did not accept the confirmation.","triggerScenarios":"http.Get succeeded but the confirmation URL returned a non-200 status: expired SubscribeURL (SNS confirms are short-lived), already-confirmed subscription, replayed/old confirmation message, or SNS-side throttling/errors.","commonSituations":"Replaying an old stored SubscriptionConfirmation payload whose token/URL has expired; double-confirming the same subscription; network middleware (corporate proxy) intercepting and returning 403/407; SNS regional endpoint issues.","solutions":["Check the logged status code: 403/410 typically means the SubscribeURL expired or token is invalid","Re-trigger the subscription from the AWS SNS console so a fresh SubscriptionConfirmation with a new URL is sent","Confirm the notification being processed is a live SNS message, not a replayed/stored sample","If a proxy returns the non-200, bypass it for *.amazonaws.com"],"exampleFix":"// before: replaying an old saved SNS test payload (expired URL) -> 403\n// after: request a new confirmation\naws sns subscribe --topic-arn arn:aws:sns:us-east-1:1:t --protocol https --notification-endpoint https://your-host/webhook/ses\n# then let the fresh SubscriptionConfirmation hit the endpoint","handlingStrategy":"retry","validationCode":"u := n.SubscribeURL // only pass SNS-hosted URLs\nparsed, err := url.Parse(u)\nvalid := err == nil && strings.HasSuffix(parsed.Hostname(), \".amazonaws.com\")\n// ensure the URL is a fresh, valid SNS confirmation URL before GET","typeGuard":null,"tryCatchPattern":"err := handler.ProcessSubscription(body)\nif err != nil {\n    var code string\n    if _, e := fmt.Sscanf(err.Error(), \"non 200 response on subscription URL: %s\", &code); e == nil {\n        log.Printf(\"SNS confirmation rejected (%s); request a fresh subscription\", code)\n        // 403/410 => expired or replayed URL: re-subscribe via AWS CLI/console\n        http.Error(w, \"subscription not confirmed\", http.StatusBadGateway)\n        return\n    }\n    http.Error(w, \"webhook error\", http.StatusInternalServerError)\n}","preventionTips":["Always process live SNS confirmations; never replay stored sample payloads","Re-subscribe from the AWS console if a confirmation has aged out","Bypass intercepting proxies for *.amazonaws.com","Watch for duplicate confirmations and ignore already-confirmed topics"],"tags":["network","http","aws","sns","webhook"],"backgroundTag":"http-4xx-response","analyzedSha":"670c01717d48647093335cc23a6be6f4b79c3b6b","analyzedAt":"2026-09-01T03:39:35.452Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}