hashicorp/terraform · error

failed to read module manifest

Error message

failed to read module manifest: %s

What it means

When constructing a config loader, Terraform reads the module manifest snapshot (a JSON file tracking installed modules under .terraform/modules/). If this file cannot be read or parsed — corrupt JSON, missing file when modules were partially installed, or a permission error — the loader cannot be created and the error propagates.

Solutions

  1. Run terraform init to regenerate the module manifest from scratch.
  2. If .terraform is corrupt, remove it entirely: rm -rf .terraform && terraform init.
  3. Check file permissions on .terraform/modules/modules.json and ensure the Terraform process can read it.
  4. Avoid running multiple terraform init processes concurrently in the same working directory.

Example fix

# before — partial/corrupt module manifest from interrupted init
terraform plan  # → error

# after — clean reinitialize
rm -rf .terraform
terraform init
terraform plan
Defensive patterns

Strategy: validation

Validate before calling

// Verify the module manifest is readable before plan
// Shell pre-check:
//   terraform init -input=false  # regenerates manifest if corrupt
// If init itself fails:
//   rm -rf .terraform && terraform init

// Go-side (embedding Terraform): wrap loader creation in error handling
loader, err := configload.NewLoader(cfg)
if err != nil {
    log.Printf("module manifest load failed, attempting clean init: %v", err)
    os.RemoveAll(filepath.Join(workingDir, ".terraform"))
    // re-run init, then retry
}

Prevention

When it happens

Trigger: Loader instantiation calls readModuleManifestSnapshot(), which fails. Triggered by: .terraform/modules/modules.json being corrupt or truncated, a partial terraform init that wrote a half-finished manifest, file permission issues on the modules directory, or a race condition where the manifest was being written when Terraform tried to read it.

Common situations: A previous terraform init was interrupted (Ctrl+C, crash, OOM kill), leaving a partial manifest file. The .terraform directory was partially deleted or restored from backup. Filesystem corruption on the modules directory. Concurrent Terraform processes racing on the same working directory.

Related errors


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

Appendix: source

Thrown at internal/configs/configload/loader.go:92

	parser := configs.NewParser(fs)
	reg := registry.NewClient(config.Services, nil)

	ret := &Loader{
		parser: parser,
		modules: moduleMgr{
			FS:         afero.Afero{Fs: fs},
			CanInstall: true,
			Dir:        config.ModulesDir,
			Services:   config.Services,
			Registry:   reg,
		},
		parserOpts: make([]configs.Option, 0),
	}

	err := ret.modules.readModuleManifestSnapshot()
	if err != nil {
		return nil, fmt.Errorf("failed to read module manifest: %s", err)
	}

	if config.IncludeQueryFiles {
		ret.parserOpts = append(ret.parserOpts, configs.MatchQueryFiles())
	}

	if config.IncludeStateMigrateFiles {
		ret.parserOpts = append(ret.parserOpts, configs.MatchStateMigrateFiles())
	}

	return ret, nil
}

// ModulesDir returns the path to the directory where the loader will look for
// the local cache of remote module packages.
func (l *Loader) ModulesDir() string {
	return l.modules.Dir
}

View on GitHub (pinned to d32a084675)