{"record":{"id":"f34c50e4247552a9","repo":"bytebase/bytebase","slug":"failed-to-read-post-webhook-response-from-s-f34c50","errorCode":null,"errorMessage":"failed to read POST webhook response from %s","messagePattern":"failed to read POST webhook response from (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/webhook/discord/discord.go","lineNumber":115,"sourceCode":"\t}\n\treq, err := http.NewRequest(\"POST\",\n\t\tcontext.URL, bytes.NewBuffer(body))\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"failed to construct webhook POST request to %s\", context.URL)\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tclient := &http.Client{\n\t\tTimeout: webhook.Timeout,\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"failed to POST webhook to %s\", context.URL)\n\t}\n\n\tb, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"failed to read POST webhook response from %s\", context.URL)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {\n\t\treturn errors.Errorf(\"failed to POST webhook %s, status code: %d, response body: %s\", context.URL, resp.StatusCode, b)\n\t}\n\tif resp.StatusCode == http.StatusNoContent || len(b) == 0 {\n\t\treturn nil\n\t}\n\n\twebhookResponse := &WebhookResponse{}\n\tif err := json.Unmarshal(b, webhookResponse); err != nil {\n\t\treturn errors.Wrapf(err, \"malformed webhook response from %s\", context.URL)\n\t}\n\n\tif webhookResponse.Code != 0 {\n\t\treturn errors.Errorf(\"%s\", webhookResponse.Message)\n\t}","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/webhook/discord/discord.go#L97-L133","documentation":"This error wraps a failure reading the full HTTP response body (io.ReadAll) after POSTing to the Discord webhook. It means the connection broke mid-read or a Body wrapper misbehaved — the response status is unknown.","triggerScenarios":"io.ReadAll(resp.Body) returns an error immediately after a successful client.Do — connection reset by peer, truncated response, or closed underlying connection.","commonSituations":"Discord or an intermediary proxy resets the connection mid-response; network interruption during read; very large/unexpected response with flaky link.","solutions":["Retry the webhook POST — this is typically transient.","Check network stability/proxy health between the server and discord.com.","If persistent, inspect proxy/MTU issues that corrupt long responses."],"exampleFix":"// before\nb, err := io.ReadAll(resp.Body)\nif err != nil {\n  return errors.Wrapf(err, \"failed to read POST webhook response from %s\", context.URL)\n}\n// after\nb, err := io.ReadAll(resp.Body)\nif err != nil {\n  return retryable(errors.Wrapf(err, \"failed to read POST webhook response from %s\", context.URL))\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := discord.Post(ctx, whCtx); err != nil {\n  if strings.Contains(err.Error(), \"failed to read POST webhook response\") {\n    // transient read failure — safe to retry the whole POST (use idempotent content)\n    return retryWithBackoff(func() error { return discord.Post(ctx, whCtx) })\n  }\n  return err\n}","preventionTips":["Retry the POST on body-read failures — the message may or may not have been delivered.","Monitor proxy/network stability for long-lived HTTP responses.","Prefer stable network paths to discord.com (avoid flaky egress)."],"tags":["webhook","discord","network","http","io"],"backgroundTag":"http-request-failed","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}