{"record":{"id":"38253dbd302f6a86","repo":"hashicorp/terraform","slug":"error-parsing-s3-url-s","errorCode":null,"errorMessage":"error parsing S3 URL: %s","messagePattern":"error parsing S3 URL: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getmodules/moduleaddrs/detect_s3.go","lineNumber":46,"sourceCode":"\t\t\treturn detectS3PathStyle(hostParts[0], parts[1:])\n\t\t} else if len(hostParts) == 4 {\n\t\t\treturn detectS3OldVhostStyle(hostParts[1], hostParts[0], parts[1:])\n\t\t} else if len(hostParts) == 5 && hostParts[1] == \"s3\" {\n\t\t\treturn detectS3NewVhostStyle(hostParts[2], hostParts[0], parts[1:])\n\t\t} else {\n\t\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\t\"URL is not a valid S3 URL\")\n\t\t}\n\t}\n\n\treturn \"\", false, nil\n}\n\nfunc detectS3PathStyle(region string, parts []string) (string, bool, error) {\n\turlStr := fmt.Sprintf(\"https://%s.amazonaws.com/%s\", region, strings.Join(parts, \"/\"))\n\turl, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"error parsing S3 URL: %s\", err)\n\t}\n\n\treturn \"s3::\" + url.String(), true, nil\n}\n\nfunc detectS3OldVhostStyle(region, bucket string, parts []string) (string, bool, error) {\n\turlStr := fmt.Sprintf(\"https://%s.amazonaws.com/%s/%s\", region, bucket, strings.Join(parts, \"/\"))\n\turl, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"error parsing S3 URL: %s\", err)\n\t}\n\n\treturn \"s3::\" + url.String(), true, nil\n}\n\nfunc detectS3NewVhostStyle(region, bucket string, parts []string) (string, bool, error) {\n\turlStr := fmt.Sprintf(\"https://s3.%s.amazonaws.com/%s/%s\", region, bucket, strings.Join(parts, \"/\"))\n\turl, err := url.Parse(urlStr)","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/getmodules/moduleaddrs/detect_s3.go#L28-L64","documentation":"Raised in detectS3PathStyle (internal/getmodules/moduleaddrs/detect_s3.go:46). After recognizing a 3-label path-style host (region.amazonaws.com), the code builds 'https://<region>.amazonaws.com/<parts...>' and calls url.Parse on it. If parsing fails (e.g. illegal characters in the bucket/key that survive string concatenation but break the URL grammar), this error wraps the underlying parse error.","triggerScenarios":"A bucket or key name containing characters url.Parse rejects (spaces, control characters, or malformed escapes) in a path-style S3 reference such as 's3.amazonaws.com/bucket/my key'.","commonSituations":"S3 object keys with spaces or non-ASCII characters that were not URL-encoded; templated keys that inject raw special characters.","solutions":["URL-encode bucket and key segments before composing the source string.","Avoid spaces and control characters in S3 object keys used as module sources.","Switch to the explicit s3::https://... form with properly encoded path components."],"exampleFix":"// before\nmodule \"x\" { source = \"s3.amazonaws.com/bucket/my module\" }\n// after\nmodule \"x\" { source = \"s3.amazonaws.com/bucket/my%20module\" }","handlingStrategy":"try-catch","validationCode":"// Pre-encode path-style S3 bucket/key segments so the reconstructed URL parses.\nfunc encodeS3PathSegments(src string) string {\n\tif !strings.Contains(src, \".amazonaws.com/\") {\n\t\treturn src\n\t}\n\tparts := strings.SplitN(src, \"/\", 2)\n\tif len(parts) != 2 {\n\t\treturn src\n\t}\n\tenc := make([]string, 0, len(strings.Split(parts[1], \"/\")))\n\tfor _, seg := range strings.Split(parts[1], \"/\") {\n\t\tenc = append(enc, url.PathEscape(seg))\n\t}\n\treturn parts[0] + \"/\" + strings.Join(enc, \"/\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := url.Parse(\"https://\" + reconstructed); err != nil {\n    return fmt.Errorf(\"reconstructed S3 URL is invalid; encode bucket/key segments: %w\", err)\n}","preventionTips":["URL-encode bucket and key segments before composing an S3 source.","Avoid spaces and control characters in S3 object keys.","Prefer the explicit s3::https:// form with encoded path components."],"tags":["s3","url-parsing","module-source"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}