{"record":{"id":"80ba5d21220b6bbd","repo":"gastownhall/beads","slug":"peer-name-must-start-with-a-letter-and-contain-onl-80ba5d","errorCode":null,"errorMessage":"peer name must start with a letter and contain only alphanumeric characters, hyphens, and underscores","messagePattern":"peer name must start with a letter and contain only alphanumeric characters, hyphens, and underscores","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/federation.go","lineNumber":25,"sourceCode":"\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/steveyegge/beads/internal/storage\"\n)\n\n// validPeerNameRegex matches valid peer names (alphanumeric, hyphens, underscores).\nvar validPeerNameRegex = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`)\n\n// ValidatePeerName checks that a peer name is safe for use as a Dolt remote name.\nfunc ValidatePeerName(name string) error {\n\tif name == \"\" {\n\t\treturn fmt.Errorf(\"peer name cannot be empty\")\n\t}\n\tif len(name) > 64 {\n\t\treturn fmt.Errorf(\"peer name too long (max 64 characters)\")\n\t}\n\tif !validPeerNameRegex.MatchString(name) {\n\t\treturn fmt.Errorf(\"peer name must start with a letter and contain only alphanumeric characters, hyphens, and underscores\")\n\t}\n\treturn nil\n}\n\n// AddFederationPeerInTx upserts a federation peer record. The encryptedPwd\n// should already be encrypted by the caller; pass nil for no password.\nfunc AddFederationPeerInTx(ctx context.Context, tx *sql.Tx, peer *storage.FederationPeer, encryptedPwd []byte) error {\n\tif err := ValidatePeerName(peer.Name); err != nil {\n\t\treturn fmt.Errorf(\"invalid peer name: %w\", err)\n\t}\n\n\t_, err := tx.ExecContext(ctx, `\n\t\tINSERT INTO federation_peers (name, remote_url, username, password_encrypted, sovereignty)\n\t\tVALUES (?, ?, ?, ?, ?)\n\t\tON DUPLICATE KEY UPDATE\n\t\t\tremote_url = VALUES(remote_url),\n\t\t\tusername = VALUES(username),\n\t\t\tpassword_encrypted = VALUES(password_encrypted),","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/federation.go#L7-L43","documentation":"ValidatePeerName requires peer names to match ^[a-zA-Z][a-zA-Z0-9_-]*$: they must start with a letter and contain only alphanumerics, hyphens, and underscores. This guarantees the name is safe as a Dolt remote identifier (no spaces, slashes, or leading digits/symbols). Names failing the regex get this error.","triggerScenarios":"Calling ValidatePeerName or AddFederationPeerInTx with names like \"1st-peer\" (leading digit), \"my peer\" (space), \"org/repo\" (slash), \"-peer\" (leading hyphen), or names with punctuation.","commonSituations":"Using a hostname or URL as the peer name (contains dots/slashes); human-entered names with spaces; auto-generated names starting with a digit or underscore-derived prefix.","solutions":["Rewrite the peer name to start with a letter and use only letters, digits, hyphens, and underscores (e.g. \"peer-1\").","Sanitize/normalize names in your config loader (strip invalid characters, prefix a letter if it starts with a digit).","Call ValidatePeerName early (at config parse time) so invalid names fail before federation setup."],"exampleFix":"// before\npeer := \"1st office peer\"\n// after\npeer := \"office-peer-1\" // matches ^[a-zA-Z][a-zA-Z0-9_-]*$","handlingStrategy":"validation","validationCode":"var peerNameRe = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`)\nif !peerNameRe.MatchString(name) {\n\treturn fmt.Errorf(\"peer name %q must start with a letter and use only [a-zA-Z0-9_-]\", name)\n}","typeGuard":"func validPeerName(name string) bool {\n\tvar re = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`)\n\treturn re.MatchString(name)\n}","tryCatchPattern":"if err := ValidatePeerName(peer); err != nil {\n\treturn fmt.Errorf(\"peer %q: %w\", peer, err)\n}","preventionTips":["Sanitize peer names on input: replace spaces/dots/slashes with hyphens, prefix a letter if it starts with a digit.","Never use hostnames, URLs, or paths as peer names.","Run ValidatePeerName at config-parse time so bad names fail before federation setup."],"tags":["validation","federation","peer-name","naming"],"backgroundTag":"peer-name-invalid","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}