{"record":{"id":"8a81bda25b51fa45","repo":"gorilla/websocket","slug":"malformed-ws-or-wss-url","errorCode":null,"errorMessage":"malformed ws or wss URL","messagePattern":"malformed ws or wss URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client.go","lineNumber":135,"sourceCode":"\n\t// EnableCompression specifies if the client should attempt to negotiate\n\t// per message compression (RFC 7692). Setting this value to true does not\n\t// guarantee that compression will be supported. Currently only \"no context\n\t// takeover\" modes are supported.\n\tEnableCompression bool\n\n\t// Jar specifies the cookie jar.\n\t// If Jar is nil, cookies are not sent in requests and ignored\n\t// in responses.\n\tJar http.CookieJar\n}\n\n// Dial creates a new client connection by calling DialContext with a background context.\nfunc (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {\n\treturn d.DialContext(context.Background(), urlStr, requestHeader)\n}\n\nvar errMalformedURL = errors.New(\"malformed ws or wss URL\")\n\nfunc hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {\n\thostPort = u.Host\n\thostNoPort = u.Host\n\tif i := strings.LastIndex(u.Host, \":\"); i > strings.LastIndex(u.Host, \"]\") {\n\t\thostNoPort = hostNoPort[:i]\n\t} else {\n\t\tswitch u.Scheme {\n\t\tcase \"wss\":\n\t\t\thostPort += \":443\"\n\t\tcase \"https\":\n\t\t\thostPort += \":443\"\n\t\tdefault:\n\t\t\thostPort += \":80\"\n\t\t}\n\t}\n\treturn hostPort, hostNoPort\n}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/gorilla/websocket/blob/e064f32e3674d9d79a8fd417b5bc06fa5c6cad8f/client.go#L117-L153","documentation":"errMalformedURL is returned by DialContext when the URL string passed to Dial/DialContext cannot be parsed or does not use the ws:// or wss:// scheme. DialContext parses the URL with url.Parse and then validates the scheme before connecting.","triggerScenarios":"Passing a URL string to Dialer.Dial/DialContext that fails url.Parse, or one whose scheme is not \"ws\" or \"wss\" (e.g. http://, https://, or no scheme at all).","commonSituations":"Building the URL with the http scheme by habit, forgetting the scheme when concatenating host strings, environment variables containing bare hostnames (\"example.com/socket\" instead of \"wss://example.com/socket\"), or typos like ws:/ or wss//.","solutions":["Ensure the URL starts with ws:// or wss:// and parses with url.Parse","Prefer ws+tls-free ws:// for plaintext and wss:// for TLS; never use http(s) scheme strings","Validate the scheme in config-loading code before constructing the dialer","Use url.Parse yourself and check err and u.Scheme to surface a clearer message"],"exampleFix":"// before\nu := os.Getenv(\"WS_URL\") // e.g. \"example.com/ws\"\nconn, _, err := dialer.Dial(u, nil)\n// after\nu := os.Getenv(\"WS_URL\")\nif !strings.HasPrefix(u, \"ws://\") && !strings.HasPrefix(u, \"wss://\") {\n    u = \"wss://\" + u\n}\nconn, _, err := dialer.Dial(u, nil)","handlingStrategy":"validation","validationCode":"func validateWSURL(raw string) error {\n    u, err := url.Parse(raw)\n    if err != nil {\n        return err\n    }\n    if u.Scheme != \"ws\" && u.Scheme != \"wss\" {\n        return fmt.Errorf(\"scheme must be ws or wss, got %q\", u.Scheme)\n    }\n    if u.Host == \"\" {\n        return errors.New(\"missing host\")\n    }\n    return nil\n}","typeGuard":"func isWSURL(raw string) bool {\n    u, err := url.Parse(raw)\n    return err == nil && (u.Scheme == \"ws\" || u.Scheme == \"wss\") && u.Host != \"\"\n}","tryCatchPattern":"if err := validateWSURL(cfg.WSURL); err != nil {\n    return fmt.Errorf(\"config error: %w\", err)\n}\nconn, _, err := dialer.DialContext(ctx, cfg.WSURL, nil)\nif err != nil {\n    return err\n}","preventionTips":["Normalize config URLs at load time, adding wss:// if the scheme is missing","Never build websocket URLs with http:// or https:// scheme strings","Add a startup-time self-check that parses and validates configured endpoints"],"tags":["websocket","url","validation"],"backgroundTag":"invalid-url-scheme","analyzedSha":"e064f32e3674d9d79a8fd417b5bc06fa5c6cad8f","analyzedAt":"2026-08-31T12:40:58.222Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}