{"record":{"id":"764f5fb6767e1b76","repo":"gastownhall/beads","slug":"remote-url-is-malformed-w","errorCode":null,"errorMessage":"remote URL is malformed: %w","messagePattern":"remote URL is malformed: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/remotecache/url.go","lineNumber":129,"sourceCode":"\t\tscheme = rawURL[:idx]\n\t\t// For net/url parsing, replace git+ssh with a parseable scheme\n\t\tif strings.HasPrefix(scheme, \"git+\") {\n\t\t\tnormalizedURL = rawURL[len(scheme)+3:] // strip scheme://\n\t\t\tnormalizedURL = \"placeholder://\" + normalizedURL\n\t\t}\n\t}\n\n\tif scheme == \"\" {\n\t\treturn fmt.Errorf(\"remote URL has no scheme (expected one of: %s)\", strings.Join(sortedSchemes(), \", \"))\n\t}\n\n\tif !allowedSchemes[scheme] {\n\t\treturn fmt.Errorf(\"remote URL scheme %q is not allowed (expected one of: %s)\", scheme, strings.Join(sortedSchemes(), \", \"))\n\t}\n\n\tparsed, err := url.Parse(normalizedURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"remote URL is malformed: %w\", err)\n\t}\n\n\t// Scheme-specific structural validation\n\tswitch scheme {\n\tcase \"dolthub\":\n\t\t// dolthub://org/repo — requires org and repo\n\t\tp := strings.TrimPrefix(parsed.Path, \"/\")\n\t\thost := parsed.Host\n\t\tcombined := host\n\t\tif p != \"\" {\n\t\t\tcombined = host + \"/\" + p\n\t\t}\n\t\tparts := strings.Split(combined, \"/\")\n\t\tif len(parts) < 2 || parts[0] == \"\" || parts[1] == \"\" {\n\t\t\treturn fmt.Errorf(\"dolthub:// URL must have org/repo format (e.g., dolthub://myorg/myrepo)\")\n\t\t}\n\tcase \"https\", \"http\", \"git+https\", \"git+http\":\n\t\tif parsed.Host == \"\" {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/remotecache/url.go#L111-L147","documentation":"The scheme passed the allowlist but net/url could not parse the (normalized) URL. The underlying url.Parse error is wrapped, so errors.Is/As against *url.Error works. For git+* schemes the library rewrites the scheme to \"placeholder\" before parsing to work around net/url limitations.","triggerScenarios":"ValidateRemoteURL with a structurally invalid URL for an allowed scheme, e.g. \"https://[bad::ipv6\", \"http://exa mple.com\", or a URL with invalid percent-encoding like \"https://h/%zz\".","commonSituations":"Copy-paste errors introducing stray spaces or brackets, shell expansions mangling the URL, or hand-assembled URLs with unescaped/invalid characters.","solutions":["Fix the URL syntax per the wrapped *url.Error message (bad host, invalid port, invalid escape)","Percent-encode special characters in path/query portions (e.g. spaces as %20)","Quote the URL in shell/config so interpolation doesn't corrupt it"],"exampleFix":"// before\nremote := \"https://my host.example.com/repo\"\n// after\nremote := \"https://my-host.example.com/repo\"","handlingStrategy":"validation","validationCode":"func parseableURL(u string) error {\n\t_, err := url.Parse(u)\n\treturn err\n}\nif err := parseableURL(remote); err != nil {\n\treturn fmt.Errorf(\"bad remote URL %q: %w\", remote, err)\n}","typeGuard":"func isParseableURL(s string) bool {\n\t_, err := url.Parse(s)\n\treturn err == nil\n}","tryCatchPattern":"if err := remotecache.ValidateRemoteURL(u); err != nil {\n\tvar urlErr *url.Error\n\tif errors.As(err, &urlErr) {\n\t\treturn fmt.Errorf(\"malformed remote URL %q: %v\", u, urlErr.Err)\n\t}\n}","preventionTips":["Run url.Parse on URLs at config-load time to fail fast","Percent-encode user-supplied path segments","Quote URLs in shell commands and config files"],"tags":["url-parsing","malformed-url","net-url"],"backgroundTag":"malformed-url","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}