hashicorp/terraform · error
error parsing S3 URL: %s
Error message
error parsing S3 URL: %s
What it means
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.
Source
Thrown at internal/getmodules/moduleaddrs/detect_s3.go:46
return detectS3PathStyle(hostParts[0], parts[1:])
} else if len(hostParts) == 4 {
return detectS3OldVhostStyle(hostParts[1], hostParts[0], parts[1:])
} else if len(hostParts) == 5 && hostParts[1] == "s3" {
return detectS3NewVhostStyle(hostParts[2], hostParts[0], parts[1:])
} else {
return "", false, fmt.Errorf(
"URL is not a valid S3 URL")
}
}
return "", false, nil
}
func detectS3PathStyle(region string, parts []string) (string, bool, error) {
urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s", region, strings.Join(parts, "/"))
url, err := url.Parse(urlStr)
if err != nil {
return "", false, fmt.Errorf("error parsing S3 URL: %s", err)
}
return "s3::" + url.String(), true, nil
}
func detectS3OldVhostStyle(region, bucket string, parts []string) (string, bool, error) {
urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s/%s", region, bucket, strings.Join(parts, "/"))
url, err := url.Parse(urlStr)
if err != nil {
return "", false, fmt.Errorf("error parsing S3 URL: %s", err)
}
return "s3::" + url.String(), true, nil
}
func detectS3NewVhostStyle(region, bucket string, parts []string) (string, bool, error) {
urlStr := fmt.Sprintf("https://s3.%s.amazonaws.com/%s/%s", region, bucket, strings.Join(parts, "/"))
url, err := url.Parse(urlStr)View on GitHub (pinned to c9def3e214)
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.
Example fix
// before
module "x" { source = "s3.amazonaws.com/bucket/my module" }
// after
module "x" { source = "s3.amazonaws.com/bucket/my%20module" } Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-encode path-style S3 bucket/key segments so the reconstructed URL parses.
func encodeS3PathSegments(src string) string {
if !strings.Contains(src, ".amazonaws.com/") {
return src
}
parts := strings.SplitN(src, "/", 2)
if len(parts) != 2 {
return src
}
enc := make([]string, 0, len(strings.Split(parts[1], "/")))
for _, seg := range strings.Split(parts[1], "/") {
enc = append(enc, url.PathEscape(seg))
}
return parts[0] + "/" + strings.Join(enc, "/")
} Try / catch
if _, err := url.Parse("https://" + reconstructed); err != nil {
return fmt.Errorf("reconstructed S3 URL is invalid; encode bucket/key segments: %w", err)
} Prevention
- 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.
When it happens
Trigger: 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'.
Common situations: S3 object keys with spaces or non-ASCII characters that were not URL-encoded; templated keys that inject raw special characters.
Related errors
- URL is not a valid S3 URL
- URL is not a valid GCS URL
- error parsing GCS URL: %s
- GitHub URLs should be github.com/username/repo
- error parsing GitHub URL: %s
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/38253dbd302f6a86.
Report an issue: GitHub.