hashicorp/terraform · error

subdir not found

Error message

subdir %q not found

What it means

Returned by ExpandSubdirGlobs when filepath.Glob of instDir/subDir yields zero matches. This typically happens for the wildcard '*' subdir used to auto-select a single nested directory: if nothing matches the pattern, the requested subdir does not exist in the extracted package. The %q is the subdir pattern.

Solutions

  1. Inspect the downloaded archive (.terraform/modules/...) to confirm the actual directory layout.
  2. Correct the subdir in the source to match a real path in the package.
  3. Pin a ref/tag known to contain the subdir.
  4. Remove the '//subdir' suffix if the module root is what you need.

Example fix

# before (subdir does not exist in v2)
source = "github.com/org/repo//modules/vpc?ref=v2.0"

# after (corrected path)
source = "github.com/org/repo//vpc?ref=v2.0"
Defensive patterns

Strategy: validation

Validate before calling

// Before ExpandSubdirGlobs, verify the subdir exists in the extracted package.
// if _, err := os.Stat(filepath.Join(instDir, subDir)); err != nil {
//     return fmt.Errorf("subdir %q not present in package; check archive layout", subDir)
// }

Prevention

When it happens

Trigger: A module source specifies '//subdir' (or relies on '*') but the downloaded archive has no entry matching that path — the package layout differs from what the source assumed.

Common situations: Module archive reorganized between versions (subdir renamed/removed); wrong tag/ref checked out; tarball published without the expected top-level folder; typo in the subdir component.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/7064cdead3eaac2b. Report an issue: GitHub.

Appendix: source

Thrown at internal/getmodules/moduleaddrs/subdir.go:89

// files on disk in the given directory which we assume contains the content
// of whichever package this is a subdirectory glob for.
//
// Subdir globs are used, for example, when a module registry wants to specify
// to select the contents of the single directory at the root of a conventional
// tar archive but it doesn't actually know the exact name of that directory.
// In that case it might specify a subdir of just "*", which this function
// will then expand into the single subdirectory found inside instDir, or
// return an error if the result would be ambiguous.
func ExpandSubdirGlobs(instDir string, subDir string) (string, error) {
	pattern := filepath.Join(instDir, subDir)

	matches, err := filepath.Glob(pattern)
	if err != nil {
		return "", err
	}

	if len(matches) == 0 {
		return "", fmt.Errorf("subdir %q not found", subDir)
	}

	if len(matches) > 1 {
		return "", fmt.Errorf("subdir %q matches multiple paths", subDir)
	}

	return matches[0], nil
}

View on GitHub (pinned to d32a084675)