hashicorp/terraform · error
can't use local directory
Error message
can't use local directory %q as a module registry address
What it means
Thrown by ParseModuleSourceRegistry when the raw source matches the local-path check (isModuleSourceLocal). This variant is explicitly registry-only and rejects anything that looks like a filesystem path so it can give a clearer error than the generic registry parser would. The %q is the raw input.
Solutions
- Replace the local path with a registry address: '<NAMESPACE>/<TYPE>/<PROVIDER>'.
- If local is intended, call ParseModuleSource (the general parser) instead of ParseModuleSourceRegistry.
- Check the calling context (CLI flag, config field) to confirm a registry address is genuinely required.
Example fix
# before (registry context, local path) source = "./modules/vpc" # after (registry address) source = "terraform-aws-modules/vpc/aws"
Defensive patterns
Strategy: type-guard
Validate before calling
// If the source might be local, do not route through ParseModuleSourceRegistry.
// if isModuleSourceLocal(raw) {
// return ParseModuleSource(raw) // general parser instead
// } Type guard
// isLocalModuleSource narrows before choosing the parser.
// func isLocalModuleSource(raw string) bool {
// return strings.HasPrefix(raw, "./") || strings.HasPrefix(raw, "../") || filepath.IsAbs(raw)
// } Prevention
- Choose ParseModuleSource (general) when source type is unknown.
- Reserve ParseModuleSourceRegistry for contexts that genuinely require a registry address.
- Validate source strings in CI to catch local paths in registry-only fields.
When it happens
Trigger: A caller that knows it expects a registry address (e.g. the module installation pipeline in registry mode) is handed a './local' or '../other' style path and refuses it up front.
Common situations: Configuration or flag meant to reference a registry module is given a local path by mistake; a wrapper tool always routes sources through the registry parser regardless of form; migrating from local to registry modules and forgetting to update one source.
Related errors
- invalid source address
- not a valid registry module source
- registry response includes invalid download URL
- registry response includes invalid download URL: must use…
- registry response includes invalid protocol string
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/b6177ec3779e4056.
Report an issue: GitHub.
Appendix: source
Thrown at internal/getmodules/moduleaddrs/source_parsing.go:156
return true
}
}
return false
}
// ParseModuleSourceRegistry is a variant of ParseModuleSource which only
// accepts module registry addresses, and will reject any other address type.
//
// Use this instead of ParseModuleSource if you know from some other surrounding
// context that an address is intended to be a registry address rather than
// some other address type, which will then allow for better error reporting
// due to the additional information about user intent.
func ParseModuleSourceRegistry(raw string) (addrs.ModuleSource, error) {
// Before we delegate to the "real" function we'll just make sure this
// doesn't look like a local source address, so we can return a better
// error message for that situation.
if isModuleSourceLocal(raw) {
return addrs.ModuleSourceRegistry{}, fmt.Errorf("can't use local directory %q as a module registry address", raw)
}
src, err := tfaddr.ParseModuleSource(raw)
if err != nil {
return nil, err
}
return addrs.ModuleSourceRegistry{
Package: src.Package,
Subdir: src.Subdir,
}, nil
}
func parseModuleSourceRemote(raw string) (addrs.ModuleSourceRemote, error) {
var subDir string
raw, subDir = SplitPackageSubdir(raw)
if strings.HasPrefix(subDir, "../") {
return addrs.ModuleSourceRemote{}, fmt.Errorf("subdirectory path %q leads outside of the module package", subDir)
}View on GitHub (pinned to d32a084675)