Terraform / Modules and state-aware lifecycle / Lesson 9
Data sources and unknown values
Distinguish reading external information from managing ownership and keep unknown future values separate from null or invalid inputs.
On this page
Lesson goals
- Explain when data-source reads can occur during plan or application.
- Design known identities without replacing unknown values with guesses.
Reading an object is not declaring its lifecycle
A managed resource describes lifecycle ownership, while a data source retrieves information through a provider-defined read interface. Reading a service does not make Terraform responsible for creating or deleting that service. The exact lookup arguments, access scope, failure behavior, and timing belong to the data source contract. Some reads involve remote APIs or supported external programs, so a data declaration is not automatically operationally inert. Review source trust and execution authority even when no managed object is intended to change.
A read requires a real ownership and access contract
The built-in terraform_remote_state data source illustrates a dependency on another configuration’s published outputs. This complete illustrative root module assumes a separately owned local snapshot at the declared path; no snapshot is supplied or read here. It is not a safe general publication channel merely because an output looks small. Access to the underlying state can expose more than the selected outputs. The backend, state identity, output names, permissions, and compatibility need review before any authorized evaluation.
terraform {
required_version = ">= 1.16.0, < 1.17.0"
}
data "terraform_remote_state" "catalog" {
backend = "local"
config = { path = "catalog-upstream.tfstate" }
}
output "upstream_name" {
value = data.terraform_remote_state.catalog.outputs.name
}
The configuration requires an approved upstream state with a name output. It does not create that state or authenticate access automatically. All HCL remains non-runnable, and the lesson never opens the path. Missing output and wrong-state selection are different failures.
Known arguments and pending changes affect read timing
Terraform normally reads a data source during planning when the required information is available, but dependencies or unknown arguments can defer its result until application. Do not assume every data value is known in every plan. Broad depends_on relationships can make the result more conservative than necessary. An unknown value represents information not yet available, not necessarily an error or absence. Configuration must preserve its type and valid dependencies while keeping instance identity decisions available at the phase that requires them.
Represent uncertainty without pretending to evaluate HCL
The offline model below uses a private sentinel to distinguish one unavailable value from a known collection of names. This is a teaching representation only; it does not reproduce Terraform’s expression evaluator, null semantics, or provider read scheduling. The known names can support stable identity reasoning even while a generated id is unavailable. Replacing that id with empty text would erase the difference between unknown and explicitly empty data, potentially hiding a real dependency rather than solving it.
unknown = object()
service_names = {'api': {}, 'worker': {}}
generated_id = unknown
print('known_keys=' + ','.join(sorted(service_names)))
print(f'generated_id_known={generated_id is not unknown}')
known_keys=api,worker
generated_id_known=False
The fixed keys remain api and worker while the sentinel indicates an unavailable id. The code reads no state or provider and does not assign a fake identity. It demonstrates information availability only, not actual Terraform planning behavior.
Prefer narrow explicit publication when ownership is separate
When another team owns the information, define a stable publication contract and access path rather than coupling consumers to a full private state representation. Specify output types, freshness expectations, missing-data behavior, and authentication. A read that succeeds may still return stale or unintended information. Validate the selected environment and object identity, and separate lookup success from application readiness. Tests should include unavailable, changed, and incompatible upstream data so consumers fail clearly instead of silently choosing a guessed fallback or managing an object they only intended to observe.
Common errors and fixes
Unsupported attribute on an upstream output.
- Why it happens
- The selected state does not publish the expected output name or shape.
- How to fix it
- Verify state identity and the producer’s versioned output contract.
- Prevent it next time
- Test upstream interface compatibility before consuming changes.
An unknown id is replaced with empty text.
- Why it happens
- Future information was mistaken for optional absence.
- How to fix it
- Preserve the dependency and redesign phase-sensitive identity decisions.
- Prevent it next time
- Test unknown, null, missing, and empty cases separately.
A data read is assumed to require no authorization.
- Why it happens
- The source’s provider, backend, or external program interactions were ignored.
- How to fix it
- Establish trusted configuration and approved access before evaluation.
- Prevent it next time
- Review read paths and credentials as operational boundaries.
Check your understanding
1. Can the fixed api and worker keys remain usable while a resource id is unknown?
Show worked solution
Yes, if the instance contract derives those keys from known declared inputs rather than the id. Keep future data inside values consumed at an appropriate phase. The example illustrates this separation, but a real configuration still needs Terraform’s own validation and dependency evaluation before use.
2. Does reading remote-state outputs grant output-only access to the snapshot?
Show worked solution
Not automatically. The consumer’s backend access can expose the underlying state, which may contain unrelated sensitive attributes. Choose the publication mechanism from the confidentiality boundary and access requirements. A narrow output expression does not itself create a narrow storage permission.
Key takeaways
- A data source observes through a contract; it does not imply ownership.
- Unknown values require phase-aware design rather than guessed replacements.