VulCode
Blog

Concourse: task file vars are interpolated before the file is parsed

A var in a non-string field such as memory: ((container_mem_limit)) failed validation, because the task file was parsed before its vars were resolved. The issue had been open since 2020.

DualFroz - VulCode CEODualFroz - VulCode CEO1 min read
Concourse: task file vars are interpolated before the file is parsed - DualFroz - VulCode CEO
Title in the repository
Interpolate task file vars before parsing the file
Merged
5 Oct 2026
Written up here
6 Oct 2026

The note was written 1 day after the change was merged.

Concourse
Technologies:GoCI/CDYAML

What was broken

Concourse is an open source CI/CD system where tasks are described in YAML files. A task file can use vars written as ((name)), for example so that a container memory limit comes from the pipeline configuration instead of being hardcoded.

The trouble started in fields that are not strings. The task file was parsed into a structure first, and the vars were only resolved afterwards. With memory: ((container_mem_limit)) the parser saw text where it expected a number, and the task failed with "cpu/memory limit must be an integer". Issue #5765, which described this, had been open since June 2020.

What we changed

The file config source can now hand back the raw file contents before they are parsed. The vars are resolved in those contents, and the result is parsed once. This early pass now runs for every task file, not only when the step sets vars:. Along the way, the error message names the file that could not be parsed, also after interpolation.

How we tested it

New tests feed a task file with cpu: ((container_cpu_limit)) and memory: ((container_mem_limit)) and the vars 512 and 5gb, then check that the limits end up as 512 and 5 GiB. A second case checks that a file that is still invalid after interpolation fails with an error naming it.

The result

The change was merged on 5 October 2026. Vars in container_limits and other numeric fields of a task file now work the way the documentation describes.

A container-based CI/CD system written in Go.

Language
Go
GitHub stars
7,915

The same calls before and after the change

The cases of the note and of the test in pull request #9717: what should come out, what came out before the fix and what comes out now.

Field in the task fileShould giveBefore the changeAfter the changeResult
Field in the task filecpu: ((container_cpu_limit))var: 512
Should give512
Before the changecpu/memory limit must be an integer
After the change512
As expected
Field in the task filememory: ((container_mem_limit))var: 5gb
Should give5 GiB
Before the changecpu/memory limit must be an integer
After the change5 GiB
As expected

2 of 2 cases as expected after the change

What we changed

The vars are resolved in the raw file contents and the result is parsed once. This runs for every task file, not only when the step sets vars:.

The second test case

A file that is still invalid after interpolation fails with an error naming that file.

What it taught us

Step order matters: variables must be substituted before the parser checks the file, or it rejects a valid configuration.

Questions about change #9717

Where the change is, how we tested it and who merged it.