{"record":{"id":"c7fae97c26492be3","repo":"hashicorp/terraform","slug":"url-is-not-a-valid-gcs-url","errorCode":null,"errorMessage":"URL is not a valid GCS URL","messagePattern":"URL is not a valid GCS URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getmodules/moduleaddrs/detect_gcs.go","lineNumber":22,"sourceCode":"package moduleaddrs\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// detectGCS detects strings that seem like schemeless references to\n// Google Cloud Storage and translates them into URLs for the \"gcs\" getter.\nfunc detectGCS(src string) (string, bool, error) {\n\tif len(src) == 0 {\n\t\treturn \"\", false, nil\n\t}\n\n\tif strings.Contains(src, \"googleapis.com/\") {\n\t\tparts := strings.Split(src, \"/\")\n\t\tif len(parts) < 5 {\n\t\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\t\"URL is not a valid GCS URL\")\n\t\t}\n\t\tversion := parts[2]\n\t\tbucket := parts[3]\n\t\tobject := strings.Join(parts[4:], \"/\")\n\n\t\turl, err := url.Parse(fmt.Sprintf(\"https://www.googleapis.com/storage/%s/%s/%s\",\n\t\t\tversion, bucket, object))\n\t\tif err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"error parsing GCS URL: %s\", err)\n\t\t}\n\n\t\treturn \"gcs::\" + url.String(), true, nil\n\t}\n\n\treturn \"\", false, nil\n}\n","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/getmodules/moduleaddrs/detect_gcs.go#L4-L40","documentation":"Thrown by detectGCS when a source string contains 'googleapis.com/' but splits into fewer than 5 slash-separated parts. The detector expects the form googleapis.com/<segment>/<version>/<bucket>/<object> (parts[0]=host, then version at parts[2], bucket at parts[3], object at parts[4:]). With too few segments there is no room for version+bucket+object, so the address is rejected as an invalid GCS URL.","triggerScenarios":"A module source like 'googleapis.com/storage/v1/bucket' (only 4 parts) or 'googleapis.com/bucket' reaches detectGCS because it contains the trigger substring, but lacks the required version/bucket/object segments.","commonSituations":"User pastes a partial GCS console URL or a bare bucket name with the googleapis.com host; misremembered GCS path format; copy-paste truncation of the object key.","solutions":["Rewrite the source as a full GCS reference including version, bucket, and object, e.g. 'googleapis.com/storage/v1/BUCKET/OBJECT'.","Prefer the explicit gcs:: form: 'gcs::https://www.googleapis.com/storage/v1/BUCKET/OBJECT' to skip fragile detection.","Verify the path in the GCS browser/console and copy the full object path before pasting."],"exampleFix":"# before (only 4 parts -> invalid)\nsource = \"googleapis.com/storage/v1/my-bucket\"\n\n# after (host/version/bucket/object)\nsource = \"googleapis.com/storage/v1/my-bucket/modules/vpc.tar.gz\"","handlingStrategy":"validation","validationCode":"// Pre-validate a GCS shorthand has at least host/segment/version/bucket/object (5 parts).\n// func validGCSShorthand(src string) error {\n//     if !strings.Contains(src, \"googleapis.com/\") { return nil }\n//     if len(strings.Split(src, \"/\")) < 5 {\n//         return fmt.Errorf(\"GCS source needs googleapis.com/<seg>/<version>/<bucket>/<object>\")\n//     }\n//     return nil\n// }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the explicit gcs::https:// form over detected shorthand.","Always copy the full object path from the GCS console.","Document the expected GCS source format in module usage guides."],"tags":["gcs","module-address","url-parsing","detection"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}