{"record":{"id":"1c35c7177a55b9d3","repo":"gastownhall/beads","slug":"remote-url-has-no-scheme-expected-one-of-s","errorCode":null,"errorMessage":"remote URL has no scheme (expected one of: %s)","messagePattern":"remote URL has no scheme \\(expected one of: (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/remotecache/url.go","lineNumber":120,"sourceCode":"\treturn validateSchemeURL(rawURL)\n}\n\n// validateSchemeURL validates a scheme-based URL (https://, dolthub://, etc.)\nfunc validateSchemeURL(rawURL string) error {\n\t// net/url doesn't understand git+ssh:// etc., so we normalize first\n\tnormalizedURL := rawURL\n\tscheme := \"\"\n\tif idx := strings.Index(rawURL, \"://\"); idx > 0 {\n\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","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/remotecache/url.go#L102-L138","documentation":"ValidateRemoteURL (via validateSchemeURL) splits the input on \"://\" to extract a scheme; if none is found, the string is not treated as a remote URL. This library only accepts dolt remote URLs with an explicit scheme (dolthub, https, s3, gs, az, oci, file, ssh, git, git+*, aws). A bare hostname or local path fails here.","triggerScenarios":"Calling remotecache.ValidateRemoteURL (or ValidateRemoteURLWithPatterns) with a string that contains no \"://\" separator and does not match the SCP pattern user@host:path, e.g. \"myorg/myrepo\" or \"example.com/repo\".","commonSituations":"Users paste a Dolthub org/repo shorthand without the dolthub:// prefix, pass a local directory path, or omit the scheme in a config file/env var where the full URL was expected.","solutions":["Add the appropriate scheme prefix, e.g. \"dolthub://myorg/myrepo\" instead of \"myorg/myrepo\"","For a local path, use \"file:///path/to/dir\" instead of a bare path","If SCP-style was intended, use the user@host:path form (e.g. git@github.com:org/repo)"],"exampleFix":"// before\nremote := \"myorg/myrepo\"\n_ = remotecache.ValidateRemoteURL(remote)\n// after\nremote := \"dolthub://myorg/myrepo\"\n_ = remotecache.ValidateRemoteURL(remote)","handlingStrategy":"validation","validationCode":"func hasScheme(u string) bool {\n\ti := strings.Index(u, \"://\")\n\treturn i > 0\n}\nif !hasScheme(remote) && !strings.Contains(remote, \"@\") {\n\tremote = \"dolthub://\" + remote // or prompt the user for a full URL\n}","typeGuard":"func isRemoteURL(s string) bool {\n\treturn strings.Contains(s, \"://\") || regexp.MustCompile(`^[^@]+@[^@]+:.+$`).MatchString(s)\n}","tryCatchPattern":"if err := remotecache.ValidateRemoteURL(u); err != nil {\n\tif strings.Contains(err.Error(), \"has no scheme\") {\n\t\tu = \"dolthub://\" + u // apply default scheme and retry\n\t}\n}","preventionTips":["Always construct remote URLs with an explicit scheme constant","Normalize user input by prefixing a default scheme when none is present","Test config parsing with URLs missing schemes"],"tags":["url-validation","scheme","remote-url"],"backgroundTag":"missing-url-scheme","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}