{"record":{"id":"94cfb89d719e674b","repo":"gastownhall/beads","slug":"invalid-url-w","errorCode":null,"errorMessage":"invalid URL: %w","messagePattern":"invalid URL: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/beads/fingerprint.go","lineNumber":83,"sourceCode":"\t}\n\n\trepoURL := strings.TrimSpace(string(output))\n\tcanonical, err := canonicalizeGitURL(repoURL)\n\tif err != nil {\n\t\treturn \"\", \"\", fmt.Errorf(\"failed to canonicalize URL: %w\", err)\n\t}\n\n\thash := sha256.Sum256([]byte(canonical))\n\treturn hex.EncodeToString(hash[:16]), RepoIDSourceRemote, nil\n}\n\nfunc canonicalizeGitURL(rawURL string) (string, error) {\n\trawURL = strings.TrimSpace(rawURL)\n\n\tif strings.Contains(rawURL, \"://\") {\n\t\tu, err := url.Parse(rawURL)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"invalid URL: %w\", err)\n\t\t}\n\n\t\thost := strings.ToLower(u.Hostname())\n\t\tif port := u.Port(); port != \"\" && port != \"22\" && port != \"80\" && port != \"443\" {\n\t\t\thost = host + \":\" + port\n\t\t}\n\n\t\tpath := strings.TrimRight(u.Path, \"/\")\n\t\tpath = strings.TrimSuffix(path, \".git\")\n\t\tpath = filepath.ToSlash(path)\n\n\t\treturn host + path, nil\n\t}\n\n\t// Detect scp-style URLs: [user@]host:path\n\t// Must contain \":\" before any \"/\" and not be a Windows path\n\tcolonIdx := strings.Index(rawURL, \":\")\n\tslashIdx := strings.Index(rawURL, \"/\")","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/beads/fingerprint.go#L65-L101","documentation":"canonicalizeGitURL parses URLs containing \"://\" with net/url to normalize them for fingerprinting. If url.Parse rejects the string, the parse error is wrapped as \"invalid URL\". This indicates the git remote value is not a syntactically valid absolute URL.","triggerScenarios":"ComputeRepoIDForPathWithSource → canonicalizeGitURL with a remote URL that contains \"://\" but fails url.Parse (invalid characters, malformed scheme/authority, control characters). Also directly exercised by TestCanonicalizeGitURL_Whitespace with malformed inputs.","commonSituations":"Typos like `https://git hub.com/repo` (space in host); stray characters or trailing whitespace/control chars from shell paste; a non-URL string in the remote slot that happens to contain \"://\".","solutions":["Run `git remote set-url origin <valid-url>` with a correctly formed URL","Validate the URL first (paste it into a browser or `python3 -c \"import urllib.parse;urllib.parse.urlparse('...')\"`)","Strip whitespace/control characters before configuring the remote","Check for shell quoting issues that embedded stray characters into .git/config"],"exampleFix":"// before\ngit remote set-url origin \"https://github.com/acme/repo.git \"\n// after\ngit remote set-url origin \"$(echo 'https://github.com/acme/repo.git' | tr -d '[:space:]')\"\n","handlingStrategy":"validation","validationCode":"_, err := url.Parse(rawRemote)\nif err != nil {\n    // remote URL invalid; fix before calling bd APIs\n}","typeGuard":null,"tryCatchPattern":"id, err := beads.ComputeRepoIDForPath(path)\nif err != nil && strings.Contains(err.Error(), \"invalid URL\") {\n    return fmt.Errorf(\"remote URL unparseable; re-set it: %w\", err)\n}","preventionTips":["Validate remote URLs with url.Parse before configuring them","Quote URLs in shell to avoid embedded stray characters","Use standard URL forms (https://host/path) for remotes","Audit .git/config after pasting URLs from terminals"],"tags":["git","url","parse"],"backgroundTag":"invalid-url-parse","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}