{"record":{"id":"7be90d56301d1d0a","repo":"sipeed/picoclaw","slug":"slack-webhook-webhook-q-has-invalid-url-format","errorCode":null,"errorMessage":"slack_webhook: webhook %q has invalid URL format: %w","messagePattern":"slack_webhook: webhook %q has invalid URL format: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/slack_webhook/slack_webhook.go","lineNumber":53,"sourceCode":"\tcfg *config.SlackWebhookSettings,\n\tbus *bus.MessageBus,\n) (*SlackWebhookChannel, error) {\n\tif len(cfg.Webhooks) == 0 {\n\t\treturn nil, fmt.Errorf(\"slack_webhook: at least one webhook target is required\")\n\t}\n\n\tif _, hasDefault := cfg.Webhooks[\"default\"]; !hasDefault {\n\t\treturn nil, fmt.Errorf(\"slack_webhook: a 'default' webhook target is required\")\n\t}\n\n\tfor name, target := range cfg.Webhooks {\n\t\twebhookURL := target.WebhookURL.String()\n\t\tif webhookURL == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"slack_webhook: webhook %q has empty webhook_url\", name)\n\t\t}\n\t\tparsed, err := url.Parse(webhookURL)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"slack_webhook: webhook %q has invalid URL format: %w\", name, err)\n\t\t}\n\t\tif !strings.EqualFold(parsed.Scheme, \"https\") {\n\t\t\treturn nil, fmt.Errorf(\"slack_webhook: webhook %q must use HTTPS (got %q)\", name, parsed.Scheme)\n\t\t}\n\t}\n\n\tbase := channels.NewBaseChannel(\n\t\t\"slack_webhook\",\n\t\tcfg,\n\t\tbus,\n\t\t[]string{\"*\"},\n\t\tchannels.WithMaxMessageLength(40000),\n\t)\n\n\treturn &SlackWebhookChannel{\n\t\tBaseChannel: base,\n\t\tbc:          bc,\n\t\tconfig:      cfg,","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/slack_webhook/slack_webhook.go#L35-L71","documentation":"During webhook validation, each webhook_url is passed through url.Parse; a parse error is wrapped as \"webhook %q has invalid URL format\". Go's url.Parse only errors on genuinely malformed input — control characters, unmatched brackets in the host, or a URL that is not absolute when later used as a request target — so this fires on corrupted values rather than merely unusual ones.","triggerScenarios":"webhook_url containing raw control characters (\\x00, \\r), a value wrapped in quotes/smart quotes copied from a rich-text editor, embedded newlines from terminal line-wrapping, or a truncated paste that leaves an unbalanced URL; note a missing scheme alone does not fail url.Parse here — it is caught by the HTTPS check instead.","commonSituations":"Copying URLs from chat/email clients that insert invisible characters or line breaks; YAML block scalars accidentally including trailing garbage; encoding mishaps (non-UTF8 bytes) after editing config on different platforms; placeholder text like ${WEBHOOK_URL} left unreplaced is usually caught by the HTTPS check, not this one.","solutions":["Re-paste the webhook URL as plain text from the Slack app settings page; strip stray whitespace, quotes, and control characters.","The wrapped error names the byte offset/reason — read errors.Unwrap(err) (a *url.Error) to find what character is offending.","Quote the value in YAML (webhook_url: \"https://...\") to avoid parser-induced mutations."],"exampleFix":"// before\nurl := webhookURLFromUser // may contain \\r\\n from clipboard\n\n// after: sanitize before saving config\ncleaned := strings.TrimSpace(strings.Map(func(r rune) rune {\n    if r < 32 { return -1 } // strip control chars\n    return r\n}, raw))\nif _, err := url.Parse(cleaned); err != nil { return fmt.Errorf(\"bad webhook_url: %w\", err) }","handlingStrategy":"validation","validationCode":"func validWebhookURL(raw string) error {\n    u, err := url.Parse(strings.TrimSpace(raw))\n    if err != nil { return fmt.Errorf(\"unparseable webhook_url: %w\", err) }\n    if u.Scheme == \"\" || u.Host == \"\" { return fmt.Errorf(\"webhook_url must be absolute\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Go: if err wraps *url.Error (errors.As) -> extract and log the parse reason; fail config validation, not runtime","preventionTips":["Paste webhook URLs as plain text; rich-text editors inject smart quotes/invisibles","Strip control characters before saving config values","Quote URL values in YAML to avoid parser mutations"],"tags":["slack-webhook","url","config","validation"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}