Terraform Error Guide: 'Failed to download module' source and auth fix
Fix Terraform's 'Failed to download module' error: correct the source address, set up git/SSH auth and tokens, pin a real ref, and re-run terraform init -upgrade.
- #terraform
- #troubleshooting
- #errors
- #modules
Exact Error Message
This error appears during terraform init, when Terraform reaches the “Initializing modules” phase and cannot fetch a module’s source. The wrapping message is Failed to download module, followed by a go-getter line explaining what went wrong:
Error: Failed to download module
Could not download module "vpc" (main.tf:8) source code from
"git::https://github.com/acme/terraform-modules.git//vpc?ref=v2.3.0":
error downloading 'https://github.com/acme/terraform-modules.git':
/usr/bin/git exited with 128:
Cloning into '.terraform/modules/vpc'...
fatal: could not read Username for 'https://github.com': terminal prompts disabled
The registry variant looks like this:
Error: Failed to download module
Could not download module "eks" (main.tf:14) source code from
"https://registry.terraform.io/v1/modules/...": error querying available
versions for module "terraform-aws-modules/eks/aws": no versions matching
"~> 99.0" found
The quoted source string and the trailing error downloading ... cause are the two pieces you need to diagnose this.
What the Error Means
Unlike Module not installed (a purely local cache problem), Failed to download module means Terraform’s installer — the go-getter library — actively tried to fetch the module source during init and the fetch failed. Terraform parses each module’s source argument, picks a fetcher (Terraform Registry, git, HTTP, S3, or local path), and clones/downloads into .terraform/modules.
The failure is at the transport or resolution layer: a malformed source address, an authentication rejection, a ref that does not exist, a network/proxy block, or a version constraint that matches no published version. The configuration syntax is valid; Terraform simply cannot retrieve the bytes. Because this happens at init time, no plan or apply runs until it is resolved.
Common Causes
- Bad source address. Mixing up registry shorthand (
terraform-aws-modules/vpc/aws), git (git::https://.../git::ssh://...), and local paths (./modules/vpc). Each fetcher has different syntax. - Git authentication for private repos. Missing SSH keys /
ssh-agent, no HTTPS token in~/.netrc, orterminal prompts disabledin CI where git cannot prompt for credentials. - A ref/tag/branch that does not exist.
?ref=v2.3.0pointing at a tag that was never pushed, renamed, or deleted. - Network, proxy, or firewall blocks. No egress to
registry.terraform.ioorgithub.com, or a corporate proxy that intercepts TLS. go-gettersubdir (//) syntax mistakes. Wrong placement of the//that separates the repo from the subdirectory within it.- Registry module not published or version constraint unmet. A
versionconstraint like~> 99.0that no published release satisfies, or a private registry module that was never published.
How to Reproduce the Error
Point a module at a private git repo from an environment with no credentials:
# main.tf
module "vpc" {
source = "git::https://github.com/acme/terraform-modules.git//vpc?ref=v2.3.0"
name = "demo"
}
terraform init
Initializing modules...
Downloading git::https://github.com/acme/terraform-modules.git for vpc...
Error: Failed to download module
... /usr/bin/git exited with 128: fatal: could not read Username for 'https://github.com'
Or trigger the version variant with an impossible constraint:
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 99.0" # no such release
}
terraform init # -> no versions matching "~> 99.0" found
Diagnostic Commands
Isolate which layer is failing — address, auth, ref, or network:
# Read the exact source and ref Terraform is using
grep -rn 'source\s*=' *.tf
# Reproduce the git fetch by hand (this is what go-getter runs)
git clone --branch v2.3.0 https://github.com/acme/terraform-modules.git /tmp/m
# Confirm the ref/tag actually exists on the remote
git ls-remote --tags --heads https://github.com/acme/terraform-modules.git | grep v2.3.0
# Check connectivity to the registry / github
curl -sSI https://registry.terraform.io/.well-known/terraform.json
curl -sSI https://github.com
# Confirm SSH auth works for git:: ssh sources
ssh -T git@github.com
If git clone by hand fails the same way, the problem is git auth or the ref — not Terraform.
Step-by-Step Resolution
1. Fix the source address for the fetcher you actually want.
# Public registry module
source = "terraform-aws-modules/vpc/aws"
version = "5.8.1"
# Git over SSH (uses your SSH key / ssh-agent)
source = "git::ssh://git@github.com/acme/terraform-modules.git//vpc?ref=v2.3.0"
# Local path (no download)
source = "./modules/vpc"
2. Provide git credentials. For SSH, load your key into the agent:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
For HTTPS private repos, add a token to ~/.netrc (or _netrc on Windows):
machine github.com
login x-access-token
password ghp_yourPersonalAccessToken
In CI, inject the token and rewrite git URLs:
git config --global url."https://x-access-token:${GH_TOKEN}@github.com/".insteadOf "https://github.com/"
3. Point ?ref= at a ref that exists. Verify with git ls-remote (above), then correct the tag/branch/commit:
source = "git::https://github.com/acme/terraform-modules.git//vpc?ref=v2.4.1"
4. Fix // subdir syntax. The // separates the repo from the subdirectory; everything after it is a path inside the repo:
git::https://host/org/repo.git//path/to/module?ref=TAG
^^ repo ends here, subdir begins
5. Loosen or correct the registry version constraint so a published release matches, then re-resolve:
version = "~> 20.0" # matches a real published release
terraform init -upgrade
6. Clear stale partial downloads and re-init if a previous attempt left a half-cloned cache:
rm -rf .terraform/modules
terraform init -upgrade
Prevention and Best Practices
- Always pin git module sources with an explicit
?ref=tag or commit SHA so installs are reproducible and a moved branch never breaksinit. - Standardize on one auth mechanism per environment:
ssh-agentfor developers, a scoped token via.netrcorurl.insteadOffor CI. - Prefer the Terraform Registry with version constraints for public modules — it gives clearer “no versions matching” errors than a raw git clone.
- Verify connectivity to
registry.terraform.ioand your git host from CI runners explicitly; many failures are silent egress/proxy blocks. - Mirror critical modules in a private registry or internal git mirror so external outages cannot block your pipelines.
- When in doubt, reproduce the fetch with a manual
git clone; if that fails, Terraform was never the problem. The free incident assistant can map thego-gettererror back to address, auth, or ref. More patterns in the Terraform guides.
Related Errors
Module not installed— the module was never fetched at all becauseinitwas not run, rather than fetched-and-failed. See the Module not installed guide.Failed to query available provider packages— the provider analogue of this error; same network/auth roots, different subsystem.Error: Invalid module source address— a stricter parse-time rejection of a malformedsource, raised before any download attempt.fatal: could not read Username/Permission denied (publickey)— the underlying git auth failures that surface inside this error’sgo-gettermessage.
Frequently Asked Questions
How is this different from “Module not installed”?
Module not installed is a local cache miss — you simply have not run init. Failed to download module means init ran and the fetch itself failed (bad source, auth, ref, or network). One is fixed by running init; the other requires fixing the source or credentials before init can succeed.
My module works locally but fails in CI. Why?
Almost always git authentication. Your laptop has an SSH key and ssh-agent; the CI runner does not. Inject a token via .netrc or git config url.insteadOf, and ensure the runner has network egress to your git host.
What does the // in a git source actually do?
It separates the repository from a subdirectory inside it. git::https://host/repo.git//modules/vpc?ref=v1 clones repo and uses the modules/vpc folder as the module. Misplacing the // makes go-getter look for a path that does not exist.
Why does my version constraint return “no versions matching”?
The constraint matches no published release. Check the module’s registry page for real version numbers and loosen the constraint (for example ~> 5.0), then run terraform init -upgrade to re-resolve.
Can a corporate proxy cause this?
Yes. If the proxy intercepts TLS or blocks registry.terraform.io/github.com, the download fails. Set HTTPS_PROXY/NO_PROXY correctly and trust the proxy CA, or use an internal module mirror that is reachable.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.