{"record":{"id":"c15e2362e682d8be","repo":"hashicorp/terraform","slug":"github-urls-should-be-github-com-username-repo","errorCode":null,"errorMessage":"GitHub URLs should be github.com/username/repo","messagePattern":"GitHub URLs should be github\\.com/username/repo","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getmodules/moduleaddrs/detect_git.go","lineNumber":47,"sourceCode":"\t\treturn \"\", false, nil\n\t}\n\n\treturn \"git::\" + u.String(), true, nil\n}\n\n// detectGitHub detects shorthand schemeless references to github.com and\n// translates them into git HTTP source addresses.\nfunc detectGitHub(src string) (string, bool, error) {\n\tif len(src) == 0 {\n\t\treturn \"\", false, nil\n\t}\n\n\tif strings.HasPrefix(src, \"github.com/\") {\n\t\tsrc, rawQuery, _ := strings.Cut(src, \"?\")\n\n\t\tparts := strings.Split(src, \"/\")\n\t\tif len(parts) < 3 {\n\t\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\t\"GitHub URLs should be github.com/username/repo\")\n\t\t}\n\n\t\turlStr := fmt.Sprintf(\"https://%s\", strings.Join(parts[:3], \"/\"))\n\t\turl, err := url.Parse(urlStr)\n\t\tif err != nil {\n\t\t\treturn \"\", true, fmt.Errorf(\"error parsing GitHub URL: %s\", err)\n\t\t}\n\t\turl.RawQuery = rawQuery\n\n\t\tif !strings.HasSuffix(url.Path, \".git\") {\n\t\t\turl.Path += \".git\"\n\t\t}\n\n\t\tif len(parts) > 3 {\n\t\t\turl.Path += \"//\" + strings.Join(parts[3:], \"/\")\n\t\t}\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/getmodules/moduleaddrs/detect_git.go#L29-L65","documentation":"Thrown by detectGitHub when a source starting with 'github.com/' splits into fewer than 3 parts. The detector requires at minimum host/username/repo (parts[0..2]); anything shorter has no repo component and cannot form a valid git HTTP address.","triggerScenarios":"Source is 'github.com/' alone or 'github.com/<username>' with no repo segment; the prefix matches but the path is incomplete.","commonSituations":"User copies only the org/profile URL instead of a repository URL; trailing slash artifacts; autocomplete/copy mistake.","solutions":["Provide the full repository path: 'github.com/USERNAME/REPO'.","Copy the URL directly from the GitHub repo page (including the repo name).","Optionally append ref via query string: 'github.com/USERNAME/REPO?ref=v1.2.3'."],"exampleFix":"# before (no repo)\nsource = \"github.com/hashicorp\"\n\n# after\nsource = \"github.com/hashicorp/example\"","handlingStrategy":"validation","validationCode":"// Validate a GitHub shorthand has at least host/user/repo.\n// func validGitHubShorthand(src string) error {\n//     if !strings.HasPrefix(src, \"github.com/\") { return nil }\n//     if len(strings.Split(src, \"/\")) < 3 {\n//         return fmt.Errorf(\"GitHub source must be github.com/USER/REPO\")\n//     }\n//     return nil\n// }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy repository URLs straight from the GitHub repo page.","Always include both username and repo segments.","Lint module sources in CI with a regex like ^github\\.com/[^/]+/[^/]+."],"tags":["github","module-address","detection"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}