{"record":{"id":"821e156ed7888e53","repo":"GopeedLab/gopeed","slug":"webhook-test-failed-s-returned-status-d","errorCode":null,"errorMessage":"webhook test failed: %s returned status %d","messagePattern":"webhook test failed: (.+?) returned status (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/download/webhook.go","lineNumber":225,"sourceCode":"\t\t},\n\t}\n\n\t// Create test data\n\ttestData := &WebhookData{\n\t\tEvent: WebhookEventDownloadDone,\n\t\tTime:  time.Now().UnixMilli(),\n\t\tPayload: &WebhookPayload{\n\t\t\tTask: testTask,\n\t\t},\n\t}\n\n\tstatusCode, err := d.sendWebhookToUrl(url, testData)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif statusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"webhook test failed: %s returned status %d\", url, statusCode)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":207,"sourceCodeEnd":230,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/pkg/download/webhook.go#L207-L230","documentation":"Returned by TestWebhookUrl (webhook.go:187-229) when the endpoint answered but with any status other than exactly HTTP 200. The test posts a simulated DOWNLOAD_DONE payload and treats only StatusOK as success (webhook.go:224-226), so 201, 204, 3xx after redirects, 4xx and 5xx all fail. It verifies end-to-end reachability and receiver acceptance of the JSON body, not just DNS/TCP connectivity (transport failures return the underlying error instead).","triggerScenarios":"Pointing the test at a receiver that replies 204 No Content (Discord-style acknowledgers), an endpoint requiring authentication (401/403), a gateway returning 502/503 transiently, a URL that redirects to a page returning a non-200, or a receiver that validates the payload and rejects the simulated task with 400.","commonSituations":"Slack/Discord/Teams-style integrations whose webhooks return 204 on success; reverse proxies or auth layers (Basic auth, API keys, IP allowlists) in front of the receiver; receivers that 400 on the synthetic test task because it references example.com; flaky upstreams during incident windows.","solutions":["Check the receiver's actual response code (curl -i -X POST with a JSON body) and, if it legitimately answers 204 on success, treat the gopeed test failure as a known limitation rather than a broken webhook","Add missing authentication (token header/basic auth) at the receiver or strip it in the proxy in front of it","Ensure the endpoint responds 200 to an application/json POST of a WebhookData-shaped body","Retry the test after transient 5xx clears; verify the URL is the POST endpoint, not a GET page"],"exampleFix":"# before\nreceiver: return 204 No Content on delivery -> gopeed test fails\n\n# after (receiver returns explicit 200)\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\"ok\":true}","handlingStrategy":"try-catch","validationCode":"u, err := neturl.Parse(url)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n\treturn fmt.Errorf(\"invalid webhook url %q\", url)\n}","typeGuard":null,"tryCatchPattern":"if err := downloader.TestWebhookUrl(u); err != nil {\n\tvar msg string\n\tif strings.Contains(err.Error(), \"returned status\") {\n\t\tmsg = fmt.Sprintf(\"receiver rejected test payload: %v (note: endpoints answering 204 fail this test by design)\", err)\n\t} else {\n\t\tmsg = fmt.Sprintf(\"webhook unreachable: %v\", err)\n\t}\n\treturn fmt.Errorf(\"%s\", msg)\n}","preventionTips":["Make receivers answer exactly 200 to JSON POSTs if you control them","Pre-authenticate: include required tokens in the URL or drop auth for the webhook route","Distinguish transport errors from non-200 status in your handling; only the latter is receiver-side","Treat 204-answering services (Discord-style) as incompatible with the strict test"],"tags":["webhook","http","integration-testing","rest-api"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}