{"record":{"id":"fe8d60210a00a6f7","repo":"gastownhall/beads","slug":"remote-name-must-start-with-a-letter-and-contain-o","errorCode":null,"errorMessage":"remote name must start with a letter and contain only alphanumeric characters, hyphens, and underscores","messagePattern":"remote name must start with a letter and contain only alphanumeric characters, hyphens, and underscores","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/remotecache/url.go","lineNumber":203,"sourceCode":"\t}\n\treturn nil\n}\n\n// ValidateRemoteName checks that a remote name is safe for use as a Dolt\n// remote identifier. Names must start with a letter and contain only\n// alphanumeric characters, hyphens, and underscores. Max 64 characters.\nfunc ValidateRemoteName(name string) error {\n\tif name == \"\" {\n\t\treturn fmt.Errorf(\"remote name cannot be empty\")\n\t}\n\tif len(name) > 64 {\n\t\treturn fmt.Errorf(\"remote name too long (max 64 characters)\")\n\t}\n\tif strings.HasPrefix(name, \"-\") {\n\t\treturn fmt.Errorf(\"remote name must not start with a dash\")\n\t}\n\tif !validRemoteNameRegex.MatchString(name) {\n\t\treturn fmt.Errorf(\"remote name must start with a letter and contain only alphanumeric characters, hyphens, and underscores\")\n\t}\n\treturn nil\n}\n\n// MatchesRemotePattern checks whether a URL matches a glob-style pattern.\n// Patterns use path.Match semantics (e.g., \"dolthub://myorg/*\").\nfunc MatchesRemotePattern(rawURL, pattern string) bool {\n\tmatched, err := path.Match(pattern, rawURL)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn matched\n}\n\n// ValidateRemoteURLWithPatterns validates a URL and optionally checks it\n// against an allowlist of glob patterns. If patterns is empty, only\n// structural validation is performed.\nfunc ValidateRemoteURLWithPatterns(rawURL string, patterns []string) error {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/remotecache/url.go#L185-L221","documentation":"The final check enforces the full name grammar: it must start with a letter and contain only [A-Za-z0-9_-] (per validRemoteNameRegex). Anything with spaces, slashes, dots, or a non-letter first character fails here.","triggerScenarios":"Names like \"1origin\", \"my remote\", \"org/repo\", \"foo.bar\" passed to ValidateRemoteName or a remote-add flow.","commonSituations":"Users passing a URL, path, or issue key as the remote name; names with spaces from copy-paste; leading digits from generated identifiers.","solutions":["Rewrite the name to start with a letter and use only letters, digits, hyphens, underscores.","Sanitize the input: replace invalid characters with '-' and strip leading digits/dashes before calling.","Prefer short conventional aliases (origin, upstream, fork)."],"exampleFix":"// before\nValidateRemoteName(\"org/repo name\")\n// after\nValidateRemoteName(\"org-repo-name\")","handlingStrategy":"validation","validationCode":"var validRemoteName = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_-]*$`)\nif !validRemoteName.MatchString(name) {\n    return fmt.Errorf(\"invalid remote name %q\", name)\n}","typeGuard":null,"tryCatchPattern":"if err := remotecache.ValidateRemoteName(name); err != nil {\n    return fmt.Errorf(\"remote name %q rejected: %w\", name, err)\n}","preventionTips":["Normalize user input: replace invalid characters with '-' and ensure a letter first.","Use constants like 'origin'/'upstream' instead of free-form names where possible.","Unit-test name sanitization with spaces, slashes, and leading digits."],"tags":["validation","remote","naming"],"backgroundTag":"invalid-remote-name","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}