Summary
The Terraform-managed sub-agent created for a coder_devcontainer resource derives its name from the Terraform block name only. When iterating with for_each or count, every instance shares the same block name, so all sub-agents try to claim the same workspace agent name and workspace creation fails with:
insert devcontainer "repos" subagent: insert subagent:
pq: workspace agent name "repos" already exists in this workspace build
There is no attribute on coder_devcontainer to override the sub-agent name from Terraform.
Reproduction
Plan/apply this template with Coder server 2.25+ and terraform-provider-coder 2.14.0+:
locals {
repos = toset(["repo-a", "repo-b", "repo-c"])
}
resource "coder_devcontainer" "repos" {
for_each = data.coder_workspace.me.start_count > 0 ? local.repos : toset([])
agent_id = coder_agent.dev[0].id
workspace_folder = "/home/user/workspaces/${each.value}"
config_path = "/home/user/workspaces/${each.value}/.devcontainer/devcontainer.json"
}
Result: workspace build fails because all three sub-agents are named "repos".
Root cause
In coder/coder's provisioner, the sub-agent name is taken from resource.Name, which is the Terraform block name and does not include the for_each key:
https://github.com/coder/coder/blob/main/provisioner/terraform/resources.go#L466-L471
agent.Devcontainers = append(agent.Devcontainers, &proto.Devcontainer{
Id: attrs.ID,
Name: resource.Name, // no for_each key suffix
WorkspaceFolder: attrs.WorkspaceFolder,
...
})
The coder_devcontainer provider schema has no name attribute to override this:
https://github.com/coder/terraform-provider-coder/blob/main/provider/devcontainer.go
Workarounds
- Define each devcontainer with a unique resource block name instead of iterating. Does not scale.
- Wrap
coder_devcontainer in a module and call it once per repo. Scales, but introduces a module layer purely to work around this.
- Set
customizations.coder.name in each devcontainer.json. Requires a PR to every repository and leaks deployment concerns into the repo.
Proposal
Add an optional name attribute to coder_devcontainer:
resource "coder_devcontainer" "repos" {
for_each = local.repos
name = each.value # new
agent_id = coder_agent.dev[0].id
workspace_folder = "/home/user/workspaces/${each.value}"
config_path = "..."
}
When set, name takes precedence over the block name when the provisioner constructs the proto.Devcontainer. This mirrors the customizations.coder.name escape hatch on the devcontainer.json side but keeps the override in Terraform, where the rest of the iteration already lives.
Environment
- Coder server:
v2.32.0
- Coder CLI / agent:
v2.31.6+f765029
terraform-provider-coder: v2.14.0
Created on behalf of manuel.anda@torc
Summary
The Terraform-managed sub-agent created for a
coder_devcontainerresource derives its name from the Terraform block name only. When iterating withfor_eachorcount, every instance shares the same block name, so all sub-agents try to claim the same workspace agent name and workspace creation fails with:There is no attribute on
coder_devcontainerto override the sub-agent name from Terraform.Reproduction
Plan/apply this template with Coder server 2.25+ and
terraform-provider-coder2.14.0+:Result: workspace build fails because all three sub-agents are named
"repos".Root cause
In
coder/coder's provisioner, the sub-agent name is taken fromresource.Name, which is the Terraform block name and does not include thefor_eachkey:https://github.com/coder/coder/blob/main/provisioner/terraform/resources.go#L466-L471
The
coder_devcontainerprovider schema has nonameattribute to override this:https://github.com/coder/terraform-provider-coder/blob/main/provider/devcontainer.go
Workarounds
coder_devcontainerin a module and call it once per repo. Scales, but introduces a module layer purely to work around this.customizations.coder.namein eachdevcontainer.json. Requires a PR to every repository and leaks deployment concerns into the repo.Proposal
Add an optional
nameattribute tocoder_devcontainer:When set,
nametakes precedence over the block name when the provisioner constructs theproto.Devcontainer. This mirrors thecustomizations.coder.nameescape hatch on thedevcontainer.jsonside but keeps the override in Terraform, where the rest of the iteration already lives.Environment
v2.32.0v2.31.6+f765029terraform-provider-coder:v2.14.0Created on behalf of manuel.anda@torc