hashicorp/terraform · error

subdir %q not found

Error message

subdir %q not found

What it means

Raised by ExpandSubdirGlobs (internal/getmodules/moduleaddrs/subdir.go:89). This function expands a (possibly glob) subdir pattern against a real installed directory, typically after a registry-served archive is extracted. If filepath.Glob returns zero matches, the expected subdirectory is not present on disk.

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 c9def3e214)

Solutions

  1. Clear the module cache and re-download/extract so the archive layout matches expectations.
  2. Verify the archive structure (it should contain a single top-level directory when the subdir is '*').
  3. Correct the subdir name in the source address to match a directory that actually exists in the package.
  4. If you control the publishing, repackage the module so the root contains exactly one directory.
Defensive patterns

Strategy: validation

Validate before calling

// Verify the expected subdir resolves before calling ExpandSubdirGlobs.
func subdirExists(instDir, 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 under %s", subDir, instDir)
	}
	return matches[0], nil
}

Try / catch

resolved, err := moduleaddrs.ExpandSubdirGlobs(instDir, subDir)
if err != nil {
    return fmt.Errorf("cannot resolve module subdir %q in %s: %w", subDir, instDir, err)
}

Prevention

When it happens

Trigger: A registry module whose subdir spec (often '*') finds no top-level directory in the extracted archive, or a named subdir that does not exist, e.g. an archive whose contents sit at the root rather than inside a single directory.

Common situations: Non-standard archive layout (files at root instead of one wrapping directory); a typo'd subdir name in the source address; a partially extracted or corrupt cache; a registry returning an archive packed differently than expected.

Related errors


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