{"record":{"id":"594c2a7155bf563f","repo":"gastownhall/beads","slug":"invalid-remote-name-w","errorCode":null,"errorMessage":"invalid remote name: %w","messagePattern":"invalid remote name: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/doltutil/remotes.go","lineNumber":159,"sourceCode":"}\n\n// RemoteURLsMatch compares remote URLs after Dolt-compatible normalization.\nfunc RemoteURLsMatch(got, want string) bool {\n\tif got == \"\" || want == \"\" {\n\t\treturn got == want\n\t}\n\tif got == want || doltremote.Normalize(got) == doltremote.Normalize(want) {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// AddCLIRemote adds a remote at the filesystem level via dolt CLI.\n// Remote mutation should normally go through SQL; this is reserved for the\n// local CLI mirror required by subprocess push/pull/fetch routing.\nfunc AddCLIRemote(dbPath, name, url string) error {\n\tif err := remotecache.ValidateRemoteName(name); err != nil {\n\t\treturn fmt.Errorf(\"invalid remote name: %w\", err)\n\t}\n\tif err := remotecache.ValidateRemoteURL(url); err != nil {\n\t\treturn fmt.Errorf(\"invalid remote URL: %w\", err)\n\t}\n\tcmd := exec.Command(\"dolt\", \"remote\", \"add\", name, url) // #nosec G204 -- validated argv\n\tcmd.Dir = dbPath\n\tout, err := cmd.CombinedOutput()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dolt remote add failed: %s: %w\", strings.TrimSpace(string(out)), err)\n\t}\n\treturn nil\n}\n\n// RemoveCLIRemote removes a remote at the filesystem level via dolt CLI.\nfunc RemoveCLIRemote(dbPath, name string) error {\n\tif err := remotecache.ValidateRemoteName(name); err != nil {\n\t\treturn fmt.Errorf(\"invalid remote name: %w\", err)\n\t}","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/doltutil/remotes.go#L141-L177","documentation":"AddCLIRemote validates the remote name with remotecache.ValidateRemoteName before invoking 'dolt remote add'. This error wraps that validation failure, so the name never reaches the CLI. It prevents invalid names from creating broken remote configuration.","triggerScenarios":"Calling AddCLIRemote/EnsureCLIRemote with a name containing illegal characters, empty string, whitespace, path separators, or reserved/overlong names.","commonSituations":"Constructing remote names from user input or hostnames without sanitizing; template/config typos; slashes from URL fragments leaking into the name.","solutions":["Sanitize the remote name: trim spaces, strip invalid characters, lowercase, remove path separators.","Follow Dolt naming rules (alphanumeric, dash, underscore, dot; no leading dashes).","Apply the same validation (remotecache.ValidateRemoteName) before calling AddCLIRemote.","Log the offending name so users can correct their config."],"exampleFix":"// before\nname := strings.TrimSpace(userInput) // may contain spaces/slashes\n_ = doltutil.AddCLIRemote(dbPath, name, url)\n// after\nname := sanitizeRemoteName(userInput)\nif err := remotecache.ValidateRemoteName(name); err != nil {\n    return fmt.Errorf(\"rejecting remote name %q: %w\", name, err)\n}\n_ = doltutil.AddCLIRemote(dbPath, name, url)","handlingStrategy":"validation","validationCode":"var remoteNameRe = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]*$`)\nif !remoteNameRe.MatchString(name) { return fmt.Errorf(\"invalid remote name: %q\", name) }","typeGuard":null,"tryCatchPattern":"if err := doltutil.AddCLIRemote(dbPath, name, url); err != nil {\n    if strings.Contains(err.Error(), \"invalid remote name\") {\n        return fmt.Errorf(\"fix remote name %q: %w\", name, err)\n    }\n    return err\n}","preventionTips":["Sanitize user/config-supplied names before calling AddCLIRemote","Reject names with spaces, slashes, or leading dashes early","Reuse remotecache.ValidateRemoteName at the config-loading boundary"],"tags":["validation","dolt","cli","naming"],"backgroundTag":"invalid-remote-name","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}