Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for OpenTofu By James Joyner IV · · 8 min read Last reviewed Jul 2026

OpenTofu Error: 'Reference to undeclared module' in Output or Expression

Quick answer

Fix OpenTofu's 'Reference to undeclared module' error: declare the missing module block, correct the module name, or reference an output the module actually exposes.

  • #opentofu
  • #terraform
  • #iac
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this OpenTofu error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Exact Error Message


│ Error: Reference to undeclared module

│   on outputs.tf line 3, in output "vpc_id":
│    3:   value = module.network.vpc_id

│ No module call named "network" is declared in the root module.

The error names the module.<name> reference it could not resolve and states that no module block with that name is declared in the module you referenced it from.

What It Means

When you write module.network.vpc_id, OpenTofu expects a module "network" {} block in the same module, and it expects that module to expose a vpc_id output. Reference to undeclared module specifically means the first part failed: there is no module call with that name in this scope.

Module call names are just like resource and variable names — they live in a single module and do not cross the module boundary. An output, another module’s argument, or any expression that references module.something will fail if the module "something" {} block is missing, misnamed, or declared in a different module than the one doing the referencing.

Common Causes

  • The module block was never declared, but an output or expression already references it.
  • A typo: the block is module "networking" but the reference is module.network.
  • The reference lives in the root module while the module block is nested inside a child (or vice versa).
  • A module block was removed or renamed during a refactor and its references were left behind.
  • Copy-pasted output blocks from another configuration that referenced module names not present here.

Diagnostic Commands

Ask OpenTofu to pinpoint the unresolved reference:

tofu validate

List every module reference in the configuration:

grep -rn 'module\.' .

Confirm whether a matching module call exists:

grep -rn 'module "network"' .

Inspect which modules OpenTofu has actually initialized:

tofu providers
cat .terraform/modules/modules.json | tofu console

Step-by-Step Resolution

  1. Run tofu validate and read the reported file and line. The module.<name> in the message is the call that is missing.

  2. Search for a module block with that exact name in the same directory:

grep -rn 'module "network"' .
  1. If the module call is missing, declare it. The block name must match the reference exactly:
module "network" {
  source     = "./modules/network"
  cidr_block = "10.0.0.0/16"
}
  1. If the names simply differ, fix the reference or the block so they agree:
output "vpc_id" {
  value = module.network.vpc_id
}
  1. If you added the block, run init so OpenTofu downloads and records the module before planning:
tofu init
  1. Confirm the referenced output actually exists in the child module. If vpc_id is not declared as an output in ./modules/network, add it there:
# modules/network/outputs.tf
output "vpc_id" {
  value = aws_vpc.this.id
}
  1. Validate and plan:
tofu validate && tofu plan

Prevention

  • Keep module blocks and every reference to them in the same module; module names are not visible across the boundary.
  • Run tofu init after adding or renaming a module block so OpenTofu records the call before you reference it.
  • Only reference outputs a child module explicitly declares with an output block — referencing an internal resource directly is not allowed.
  • Run tofu validate in CI so undeclared module references fail before apply.
  • When renaming a module, update the block and all module.<name> references together. The prompt library has prompts that wire module outputs to root outputs consistently.
  • Reference to undeclared input variable — the same class of error for a var. reference with no variable block.
  • Unsupported attribute — the module is declared but the output name you referenced does not exist.
  • Module not installed — the module block exists but tofu init has not been run.
  • Reference to undeclared resource — a resource reference with no matching resource block.

Frequently Asked Questions

Do I need to run tofu init after adding a module block? Yes. init downloads the module source and records it in .terraform/modules. Until then, references to it will not resolve during plan.

Why can’t the root see a module declared inside a child? Module calls are scoped to the module that declares them. If the root references module.network, the module "network" block must be in the root, not nested in a child module.

The module is declared but I still get an error on the attribute — why? That is usually Unsupported attribute, meaning the module call resolves but the specific output you referenced is not declared with an output block in the child module.

Can I reference a resource inside a module directly? No. Modules encapsulate their resources. Expose what you need through output blocks in the child and reference module.name.output_name.

Where can I find more OpenTofu troubleshooting? See the OpenTofu guides for the full library of error walkthroughs.

Free download · 368-page PDF

Fixed it? Get 500 OpenTofu & DevOps AI prompts — free

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.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

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.