# Fix terraform "Error: Reference to undeclared input variable"

**TL;DR:** Your config uses `var.something` but no `variable "something"` block exists in that module. Add the variable block to `variables.tf` (or fix the typo in the name). Variables are scoped per module: a variable declared in a child module is invisible to the root, and vice versa.

## The error

```text
Error: Reference to undeclared input variable

  on main.tf line 8, in provider "aws":
   8:   region = var.aws_region

An input variable with the name "aws_region" has not been declared.
```

## Steps

1. Check for a typo first: `grep -rn 'variable "aws_region"' .` should find the declaration. Case must match exactly; `aws_Region` is a different name.
2. If it is genuinely missing, declare it in the same module's `variables.tf`:

   ```hcl
   variable "aws_region" {
     description = "AWS region for all resources"
     type        = string
     default     = "us-east-1"
   }
   ```

3. If the reference is in the root module but the variable was declared in a child module, that is the bug: child variables are module inputs, not globals. Either declare it in the root too and pass it down, or use the child's default by not referencing it at root.
4. Run `terraform validate`. Expected: `Success! The configuration is valid.`

## When this applies

- `validate` or `plan` fails with `Reference to undeclared input variable` / `has not been declared`.
- You renamed a variable, or you are wiring modules together and assumed a child variable is visible at root.

## When it does NOT apply

- `Error: Value for undeclared variable`. That is the inverse: your tfvars or `-var` flag sets a name no block declares. Remove the stray value or declare the variable.
- `Reference to undeclared resource`. Same family, different object: a resource address that does not exist.

## Tool and version compatibility

- Terraform CLI 0.12+ through 1.x. Variable scoping rules unchanged.

## Why it happens

Every `var.name` must resolve to a `variable "name"` block in the same module. There is no global scope. The common triggers are typos, half-finished renames, and the mental model that child-module variables leak upward. They do not.

## Edge cases and pitfalls

- A `variable` block with no `default` makes the variable required. If you add the block without a default, the next plan will prompt for a value. Add the default or a tfvars entry.
- Renaming a variable means updating every `var.old_name` reference AND the block. `grep -rn var.old_name .` catches stragglers.
- `.tfvars` files assigning undeclared variables fail with the inverse error, so keep the two in sync.