{"record":{"id":"91ffe69483487961","repo":"hashicorp/terraform","slug":"s-returned-from-s","errorCode":null,"errorMessage":"%s returned from %s","messagePattern":"(.+?) returned from (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getproviders/registry_client.go","lineNumber":441,"sourceCode":"\t}\n}\n\nfunc (c *registryClient) errUnauthorized(hostname svchost.Hostname) error {\n\treturn ErrUnauthorized{\n\t\tHostname:        hostname,\n\t\tHaveCredentials: c.creds != nil,\n\t}\n}\n\nfunc (c *registryClient) getFile(url *url.URL) ([]byte, error) {\n\tresp, err := c.httpClient.Get(url.String())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"%s returned from %s\", resp.Status, HostFromRequest(resp.Request))\n\t}\n\n\tdata, err := ioutil.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn data, err\n\t}\n\n\treturn data, nil\n}\n\n// configureDiscoveryRetry configures the number of retries the registry client\n// will attempt for requests with retryable errors, like 502 status codes\nfunc configureDiscoveryRetry() {\n\tdiscoveryRetry = defaultRetry\n\n\tif v := os.Getenv(registryDiscoveryRetryEnvName); v != \"\" {\n\t\tretry, err := strconv.Atoi(v)\n\t\tif err == nil && retry > 0 {","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/getproviders/registry_client.go#L423-L459","documentation":"Produced by getFile when the HTTP response status is not 200 OK while fetching a registry artifact (checksums document, signature file, etc.). The message is '<status> returned from <host>'. It surfaces the upstream status verbatim so the caller sees, for example, '404 Not Found returned from releases.hashicorp.com'.","triggerScenarios":"Any non-200 response from httpClient.Get on a fully-resolved registry URL: 404 for a missing artifact, 401/403 for unauthorized access, 5xx for upstream errors, 3xx that exhausted redirect limits.","commonSituations":"Provider version was yanked but metadata still references it (404); token expired for a private registry (401); rate-limited by registry (429); artifact path changed on the registry backend; mirror missing the specific artifact.","solutions":["Match the status: 401/403 -> refresh credentials/token; 404 -> the artifact is absent, re-check provider version; 429/5xx -> retry after backoff.","For private registries, re-login with 'terraform login <host>' to refresh the API token.","If mirror is in use, ensure the mirror sync includes checksums and signature artifacts, not just zip packages.","Raise TF_REGISTRY_DISCOVERY_RETRY and TF_REGISTRY_CLIENT_TIMEOUT if the host is flaky."],"exampleFix":"// before: stale token\n$ terraform init\nError: 401 Unauthorized returned from app.terraform.io\n// after\n$ terraform login app.terraform.io\n$ terraform init","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Match on ErrQueryFailed and inspect the wrapped message.\nvar qf getproviders.ErrQueryFailed\nif errors.As(err, &qf) {\n    msg := qf.Error()\n    if strings.Contains(msg, \"401\") || strings.Contains(msg, \"403\") { refreshCreds() }\n    if strings.Contains(msg, \"404\") { recheckProviderVersion() }\n    if strings.HasPrefix(msg, \"5\") || strings.HasPrefix(msg, \"429\") { retry() }\n}","preventionTips":["Keep registry tokens fresh via 'terraform login' on a schedule.","Mirror checksums and signatures alongside zip artifacts.","Monitor upstream registry status for outages."],"tags":["registry","http-status","network","getproviders"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}