{"record":{"id":"760d6d2250dfcf7a","repo":"bytebase/bytebase","slug":"failed-to-construct-webhook-post-request-to-s-760d6d","errorCode":null,"errorMessage":"failed to construct webhook POST request to %s","messagePattern":"failed to construct webhook POST request to (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/webhook/slack/slack.go","lineNumber":224,"sourceCode":"\tif context.DirectMessage && len(context.MentionEndUsers) > 0 {\n\t\tif postDirectMessage(context) {\n\t\t\treturn nil\n\t\t}\n\t\tslog.Warn(\"failed to send direct messages for slack users, fallback to normal webhook\", slog.String(\"event\", context.EventType))\n\t}\n\treturn postMessage(context)\n}\n\nfunc postMessage(context webhook.Context) error {\n\tpost := BuildMessage(context)\n\tbody, err := json.Marshal(post)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"failed to marshal webhook POST request to %s\", context.URL)\n\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 {","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/webhook/slack/slack.go#L206-L242","documentation":"After marshaling, postMessage builds the POST with http.NewRequest against context.URL; this error wraps any http.NewRequest failure with the target URL. NewRequest fails mainly on an unparseable URL (missing/invalid scheme) or an invalid HTTP method.","triggerScenarios":"Calling Post with a webhook context whose URL is empty, lacks an http(s) scheme, or contains characters invalid in a URL.","commonSituations":"Slack webhook URL not configured or left empty in workspace settings; URL copied with whitespace or bad scheme (e.g. 'slack.com/hooks/...' without https://); configuration template not substituted so URL contains literal placeholders.","solutions":["Validate the Slack webhook URL is a well-formed https URL before calling Post (url.ParseRequestURI and check scheme)","Fix the workspace webhook configuration so context.URL is a complete https://hooks.slack.com/... address","Trim whitespace and ensure no unresolved template placeholders remain in the configured URL"],"exampleFix":"// before\nu := settings.SlackWebhookURL // possibly empty\n// after\nu := strings.TrimSpace(settings.SlackWebhookURL)\nif _, err := url.ParseRequestURI(u); err != nil || !strings.HasPrefix(u, \"https://\") { return errors.New(\"invalid slack webhook url\") }","handlingStrategy":"validation","validationCode":"u, err := url.ParseRequestURI(strings.TrimSpace(webhookURL)); if err != nil || u.Scheme != \"https\" { return errors.New(\"invalid slack webhook url\") }","typeGuard":null,"tryCatchPattern":"if err := webhook.Post(ctx); err != nil { if strings.Contains(err.Error(), \"failed to construct webhook POST request\") { /* reconfigure URL */ } }","preventionTips":["Validate the webhook URL at workspace-settings save time, not only at send time","Reject empty or non-https URLs in configuration UI"],"tags":["slack","webhook","url","http"],"backgroundTag":"invalid-url-format","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"}