{"record":{"id":"64741e420672aab5","repo":"gastownhall/beads","slug":"dolthub-url-must-have-org-repo-format-e-g-do","errorCode":null,"errorMessage":"dolthub:// URL must have org/repo format (e.g., dolthub://myorg/myrepo)","messagePattern":"dolthub:// URL must have org/repo format \\(e\\.g\\., dolthub://myorg/myrepo\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/remotecache/url.go","lineNumber":144,"sourceCode":"\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 == \"\" {\n\t\t\treturn fmt.Errorf(\"%s:// URL must include a hostname\", scheme)\n\t\t}\n\tcase \"ssh\", \"git\", \"git+ssh\":\n\t\tif parsed.Host == \"\" {\n\t\t\treturn fmt.Errorf(\"%s:// URL must include a hostname\", scheme)\n\t\t}\n\tcase \"s3\", \"aws\", \"gs\":\n\t\t// s3://bucket/path, aws://bucket/path, gs://bucket/path — host is the bucket\n\t\tif parsed.Host == \"\" {\n\t\t\treturn fmt.Errorf(\"%s:// URL must include a bucket name\", scheme)\n\t\t}\n\tcase \"az\":\n\t\t// az://account.blob.core.windows.net/container/path\n\t\tif parsed.Host == \"\" {\n\t\t\treturn fmt.Errorf(\"az:// URL must include a storage account hostname\")","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/remotecache/url.go#L126-L162","documentation":"dolthub:// URLs must identify both an organization and a repository (dolthub://org/repo). After parsing, the host and path are combined and split on \"/\"; if there are fewer than two non-empty segments, the URL lacks an org, a repo, or both.","triggerScenarios":"ValidateRemoteURL with \"dolthub://\", \"dolthub://myorg\", \"dolthub://myorg/\", or \"dolthub:///myrepo\" — any form missing host-and-path org/repo segments.","commonSituations":"Config truncated at paste time, environment variables set to just the org, or templating that dropped the repo part of the URL.","solutions":["Include both org and repo: \"dolthub://myorg/myrepo\"","Check that config/env substitution didn't truncate the URL at the slash","If only browsing an org, use the Dolthub website — the remote URL must name a specific repo"],"exampleFix":"// before\nremote := \"dolthub://myorg/\"\n// after\nremote := \"dolthub://myorg/myrepo\"","handlingStrategy":"validation","validationCode":"func validDolthubURL(u string) bool {\n\trest, ok := strings.CutPrefix(u, \"dolthub://\")\n\tif !ok { return false }\n\tparts := strings.Split(strings.Trim(rest, \"/\"), \"/\")\n\treturn len(parts) >= 2 && parts[0] != \"\" && parts[1] != \"\"\n}","typeGuard":"func isDolthubOrgRepo(u string) bool {\n\tconst p = \"dolthub://\"\n\tif !strings.HasPrefix(u, p) { return false }\n\tparts := strings.Split(strings.Trim(u[len(p):], \"/\"), \"/\")\n\treturn len(parts) >= 2 && parts[0] != \"\" && parts[1] != \"\"\n}","tryCatchPattern":"if err := remotecache.ValidateRemoteURL(u); err != nil {\n\tif strings.Contains(err.Error(), \"org/repo format\") {\n\t\treturn fmt.Errorf(\"dolthub remote %q must be dolthub://org/repo\", u)\n\t}\n}","preventionTips":["Build dolthub URLs with fmt.Sprintf(\"dolthub://%s/%s\", org, repo)","Validate org and repo are non-empty before formatting","Add a unit test for the org/repo URL builder"],"tags":["url-validation","dolthub","remote-url"],"backgroundTag":"invalid-remote-url-format","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}