{"record":{"id":"e6eb055ce0a6d0b0","repo":"hashicorp/terraform","slug":"registry-response-includes-invalid-download-url","errorCode":null,"errorMessage":"registry response includes invalid download URL: %s","messagePattern":"registry response includes invalid download URL: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getproviders/registry_client.go","lineNumber":285,"sourceCode":"\t\tif !match {\n\t\t\t// If the protocol version is not supported, try to find the closest\n\t\t\t// matching version.\n\t\t\tclosest, err := c.findClosestProtocolCompatibleVersion(ctx, provider, version)\n\t\t\tif err != nil {\n\t\t\t\treturn PackageMeta{}, err\n\t\t\t}\n\t\t\tprotoErr.Suggestion = closest\n\t\t\treturn PackageMeta{}, protoErr\n\t\t}\n\t}\n\n\tif body.OS != target.OS || body.Arch != target.Arch {\n\t\treturn PackageMeta{}, fmt.Errorf(\"registry response to request for %s archive has incorrect target %s\", target, Platform{body.OS, body.Arch})\n\t}\n\n\tdownloadURL, err := url.Parse(body.DownloadURL)\n\tif err != nil {\n\t\treturn PackageMeta{}, fmt.Errorf(\"registry response includes invalid download URL: %s\", err)\n\t}\n\tdownloadURL = resp.Request.URL.ResolveReference(downloadURL)\n\tif downloadURL.Scheme != \"http\" && downloadURL.Scheme != \"https\" {\n\t\treturn PackageMeta{}, fmt.Errorf(\"registry response includes invalid download URL: must use http or https scheme\")\n\t}\n\n\tret := PackageMeta{\n\t\tProvider:         provider,\n\t\tVersion:          version,\n\t\tProtocolVersions: protoVersions,\n\t\tTargetPlatform: Platform{\n\t\t\tOS:   body.OS,\n\t\t\tArch: body.Arch,\n\t\t},\n\t\tFilename: body.Filename,\n\t\tLocation: PackageHTTPURL(downloadURL.String()),\n\t\t// \"Authentication\" is populated below\n\t}","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/getproviders/registry_client.go#L267-L303","documentation":"PackageMeta could not url.Parse the download_url field from the registry response, so there is no valid URL to fetch the provider archive from. The download is aborted before any network fetch with a plain fmt.Errorf wrapping the parse error.","triggerScenarios":"Registry response's download_url contains characters or structure that Go's url.Parse rejects (control chars, invalid percent-encoding, missing scheme with a colon in the wrong place).","commonSituations":"Custom registry templating bug producing a broken URL; a space or stray quote in the URL; URL built by string concatenation with an unencoded segment; registry returned an empty download_url combined with other bad characters.","solutions":["Fetch the raw download response and inspect download_url for invalid characters or encoding.","Fix the registry to emit a well-formed absolute or relative URL (relative is resolved against the request URL).","URL-encode any dynamic path segments the registry injects."],"exampleFix":"// before\n{\"download_url\":\"https://reg/p/terraform-provider v1.0.zip\"}\n// after\n{\"download_url\":\"https://reg/p/terraform-provider%20v1.0.zip\"}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"meta, err := client.PackageMeta(ctx, provider, ver, plat)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid download URL\") && !strings.Contains(err.Error(), \"scheme\") {\n        // registry returned a malformed download_url; not retryable, report upstream\n    }\n    return err\n}","preventionTips":["For private registries, lint the download_url with url.Parse in a test fixture.","URL-encode dynamic segments the registry injects into the URL.","Return absolute https URLs to avoid resolution ambiguity."],"tags":["terraform","registry","download-url","url-parsing"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}