Interpolation Syntax not consistent - AWS

Have the following JSON code that is failing. Only works when I change the variables to use the ${}. Without the old syntax it doesn’t work. Thoughts?

[
{
"resource": {
  "aws_vpc": {
    "vpc": {
      "cidr_block": "var.vpc_prefix"
    }
  }
 }
},
{
"resource": {
  "aws_subnet": {
    "servers-subnet": {
      "vpc_id": "aws_vpc.vpc.id",
      "cidr_block": "${var.subnets[0][\"addressPrefix\"]}"
    }
  }
}
},
{
"resource": {
  "aws_subnet": {
    "services-subnet": {
      "vpc_id": "aws_vpc.vpc.id",
      "cidr_block": "${var.subnets[1][\"addressPrefix\"]}"
    }
  }
}
}
]

Hi @farroar,

The behavior you’ve observed here is correct: in the JSON variant of the Terraform language, all values are literal strings by default and we use the ${ ... } syntax to introduce reference to non-literal values. This is necessary because otherwise JSON syntax alone provides no way for you to tell Terraform that "var.vpc_prefix" is intended as a reference rather than a literal string.

There’s more information on how expressions work in the JSON variant of the language in the documentation section JSON Expression Mapping. In particular, note the special case:

If the given template consists only of a single interpolation sequence, the result of its expression is taken directly, without first converting it to a string. This allows non-string expressions to be used within the JSON syntax.

That special case is not really relevant to the example you shared because it seems that var.vpc_prefix is a string value anyway, but a JSON string like "${var.example}" will produce a result of whatever type var.example has, ignoring the fact that it’s presented as a string. This is a compromise to ensure that it’s still possible to write expressions that return non-string values when using the JSON language variant.