{"record":{"id":"09f0ddde8a7bec94","repo":"hashicorp/terraform","slug":"error-parsing-gcs-url-s","errorCode":null,"errorMessage":"error parsing GCS URL: %s","messagePattern":"error parsing GCS URL: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getmodules/moduleaddrs/detect_gcs.go","lineNumber":32,"sourceCode":"func 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":14,"sourceCodeEnd":40,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/getmodules/moduleaddrs/detect_gcs.go#L14-L40","documentation":"Returned by detectGCS when url.Parse rejects the synthesized URL 'https://www.googleapis.com/storage/<version>/<bucket>/<object>'. Because the URL is built from parts that already passed the length check, a parse failure means one of the bucket/object segments contains characters illegal in a URL (control chars, spaces, invalid percent-encoding). The %s is the url.Parse error.","triggerScenarios":"A GCS object key with raw spaces, control characters, or malformed percent-encoding is concatenated into the URL string and url.Parse fails.","commonSituations":"Object keys with spaces or special characters pasted verbatim; percent-encoded keys that are already partially encoded; locale-specific characters in bucket names.","solutions":["URL-encode the bucket and object segments before constructing the source string.","Use the explicit gcs:: prefix with an already-valid https URL.","Rename the GCS object to avoid spaces/special characters and update the source."],"exampleFix":"# before (space in object key -> parse fails)\nsource = \"googleapis.com/storage/v1/bucket/my module.tar.gz\"\n\n# after (encoded)\nsource = \"gcs::https://www.googleapis.com/storage/v1/bucket/my%20module.tar.gz\"","handlingStrategy":"validation","validationCode":"// URL-encode bucket/object before building a GCS URL.\n// func buildGCSURL(version, bucket, object string) (string, error) {\n//     u := fmt.Sprintf(\"https://www.googleapis.com/storage/%s/%s/%s\",\n//         url.PathEscape(version), url.PathEscape(bucket), url.PathEscape(object))\n//     _, err := url.Parse(u)\n//     return u, err\n// }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid spaces and control characters in GCS object keys.","Use url.PathEscape on user-supplied path segments.","Use the explicit gcs:: form for non-trivial keys."],"tags":["gcs","url-parsing","encoding"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}