Build1 publisherNot yet confirmed elsewhere2 min readPublished
OpenTofu 1.13 turns documented provider guarantees into plan-time answers
OpenTofu 1.13 adds assume functions that let module authors declare an unknown value's shape, so null and prefix checks get answered at plan time. Plan reviews lean less on guesswork wherever shared modules wrap their outputs this way.
The Engineer · Build desk

What happened
- OpenTofu 1.13 shipped on September 30, a 1.13.1 patch followed on October 1, and security support for the line runs to August 2027.
- Without a hint, comparing an unknown VPC ID to null returns unknown, and any module fed that ID inherits the unknowns.
- Two companion functions ship alongside: convert declares the type of a value OpenTofu cannot infer, such as jsondecode output, and assumeequal declares the final value outright.
- An early built-in linter, run with tofu plan -lint=all, checks four rules: untyped variables, count where enabled fits, unused variables and unused locals.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- decision Module authors now have to choose which provider guarantees to encode in their outputs, and the safe set is limited to what provider or API documentation actually states.
- exposure A wrong assumption still passes plan review cleanly and surfaces only when apply fails, after the change has been approved.
- cost Upgrading carries migration work: WinRM provisioners have to move to OpenSSH, and resources that use base64gzip may show proposed diffs someone has to review.
A plan is a prediction. OpenTofu walks the configuration, calls the providers and works out what would change without changing anything [6]. It cannot ask the cloud API to create a resource, because creating resources is the job of apply [6]. Values the API picks during apply, such as an instance ID, an ARN or a load balancer's IP, therefore print as (known after apply) [7].
The 1.13 functions let a module author write down what the provider cannot promise [1]. A walkthrough published on dev.to shows it on a single output [1]:
```hcl value = assumenotnull(assumestringprefix(aws_vpc.example.id, "vpc-")) ```
According to the walkthrough, the AWS provider's API documentation guarantees that a VPC ID is never null and always starts with vpc- [3]. The nested call puts that guarantee where the planner can use it [1].
AWS still chooses the ID during apply [7]. The planner gains answers to questions about the ID. A comparison against null or the empty string returns false at plan time [2]. A downstream module that checks for the vpc- prefix runs that validation during plan, before anything is created [2].
The promise holds only until real values arrive. At apply, OpenTofu checks each assumption, and an ID promised as vpc- that comes back as subnet- fails the assumestringprefix call [10]. The walkthrough's author wrote that "the cost of lying to the planner is a failed apply rather than silent breakage" [16]. The post does not say what state that failed apply leaves when other resources in the same run were already created.
I think the checked design is correct. The walkthrough argues that an unchecked assumption would turn the plan into fiction [17]. Its rule for authors is to "only promise what the provider or the vendor API documentation actually guarantees" [11]. One upstream output wrapped this way gives known answers to the modules that consume it [2]. The rule matters most for assumeequal, which states the final value outright [9]. It is the function I'd expect to show up in incident reviews. The evidence here is one worked VPC example from a single walkthrough [1]. It shows how the functions behave on one output.
The rest of 1.13 is early work. The team shortened the cycle to match Go's release schedule, and the walkthrough credits that choice for the longer security window [5]. Symbol Libraries, an experiment for sharing values, functions and type aliases across configurations separately from modules, is still changing shape [13]. Windows on ARM64 is now an official platform [14].
What to watch
- Whether widely shared modules start wrapping provider outputs in assume calls, since downstream plans only gain known answers when upstream authors do.
- Whether Symbol Libraries leave experimental status with a settled shape in a later release.
- Whether the -lint=all rule set grows beyond its first four rules.