GopeedLab/gopeed · error
webhook test failed: %s returned status %d
Error message
webhook test failed: %s returned status %d
What it means
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).
Source
Thrown at pkg/download/webhook.go:225
},
}
// Create test data
testData := &WebhookData{
Event: WebhookEventDownloadDone,
Time: time.Now().UnixMilli(),
Payload: &WebhookPayload{
Task: testTask,
},
}
statusCode, err := d.sendWebhookToUrl(url, testData)
if err != nil {
return err
}
if statusCode != http.StatusOK {
return fmt.Errorf("webhook test failed: %s returned status %d", url, statusCode)
}
return nil
}
View on GitHub (pinned to 7b7327ffb3)
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
Example fix
# before
receiver: return 204 No Content on delivery -> gopeed test fails
# after (receiver returns explicit 200)
HTTP/1.1 200 OK
Content-Type: application/json
{"ok":true} Defensive patterns
Strategy: try-catch
Validate before calling
u, err := neturl.Parse(url)
if err != nil || u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid webhook url %q", url)
} Try / catch
if err := downloader.TestWebhookUrl(u); err != nil {
var msg string
if strings.Contains(err.Error(), "returned status") {
msg = fmt.Sprintf("receiver rejected test payload: %v (note: endpoints answering 204 fail this test by design)", err)
} else {
msg = fmt.Sprintf("webhook unreachable: %v", err)
}
return fmt.Errorf("%s", msg)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- webhook URL is empty
- redirect failed
- too many redirects
- invalid range
- connection %d failed: retries=%d, status=%d
AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16).
Data as JSON: /api/errors/821e156ed7888e53.
Report an issue: GitHub.