{"record":{"id":"0ede26d4c4fadd7d","repo":"hashicorp/terraform","slug":"url-is-not-a-valid-s3-url","errorCode":null,"errorMessage":"URL is not a valid S3 URL","messagePattern":"URL is not a valid S3 URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getmodules/moduleaddrs/detect_s3.go","lineNumber":22,"sourceCode":"package moduleaddrs\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// detectS3 detects strings that seem like schemeless references to\n// Amazon S3 and translates them into URLs for the \"s3\" getter.\nfunc detectS3(src string) (string, bool, error) {\n\tif len(src) == 0 {\n\t\treturn \"\", false, nil\n\t}\n\n\tif strings.Contains(src, \".amazonaws.com/\") {\n\t\tparts := strings.Split(src, \"/\")\n\t\tif len(parts) < 2 {\n\t\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\t\"URL is not a valid S3 URL\")\n\t\t}\n\n\t\thostParts := strings.Split(parts[0], \".\")\n\t\tif len(hostParts) == 3 {\n\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}","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/getmodules/moduleaddrs/detect_s3.go#L4-L40","documentation":"First S3 validity check in detectS3: the source contains '.amazonaws.com/' but splits into fewer than 2 parts, meaning there is no path after the host. The detector needs at least host + one path segment to identify a bucket/key, so it rejects the URL.","triggerScenarios":"Source is just 'something.amazonaws.com/' with no bucket or key path; the trigger substring matched but no object path follows.","commonSituations":"User pastes only the S3 endpoint host; bare region endpoint with no bucket; copy-paste truncation losing the key.","solutions":["Provide the full path including bucket and key: '<region>.amazonaws.com/BUCKET/KEY'.","Prefer the explicit s3:: form: 's3::https://<host>/<bucket>/<key>'.","Copy the full object path from the S3 console."],"exampleFix":"# before (no path)\nsource = \"s3.amazonaws.com/\"\n\n# after\nsource = \"s3.amazonaws.com/my-bucket/modules/vpc.zip\"","handlingStrategy":"validation","validationCode":"// Ensure an S3-ish source has a path after the host.\n// func validS3HasPath(src string) error {\n//     if !strings.Contains(src, \".amazonaws.com/\") { return nil }\n//     if len(strings.Split(src, \"/\")) < 2 {\n//         return fmt.Errorf(\"S3 source needs bucket and key after the host\")\n//     }\n//     return nil\n// }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include bucket and key in S3 sources.","Prefer the explicit s3::https:// form.","Copy the full object path from the S3 console."],"tags":["s3","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"}