How to fix Error: Invalid JSON syntax in Terraform

TerraformINTERMEDIATEMEDIUMUpdated Dec 30, 2025· 123 views

This error occurs when Terraform detects malformed JSON in your configuration, typically in JSON-encoded strings, heredocs, or when mixing HCL with inline JSON. JSON requires proper structure with quoted keys, commas, and no trailing commas.

Quick fix

Fixes Error: Invalid JSON syntax

Error: Invalid JSON syntax: ...
  on main.tf line 42, in resource "aws_iam_role_policy" "example":
   42:   policy = jsonencode({
  1. Identify the exact JSON causing the error
  2. Check for trailing commas
  3. Verify all JSON keys and strings are properly quoted
  4. Check quote escaping in JSON strings
terraform — error
Error: Invalid JSON syntax: ...
on main.tf line 42, in resource "aws_iam_role_policy" "example":
42: policy = jsonencode({
Error: Invalid JSON syntax

What this error means

The "Invalid JSON syntax" error indicates that Terraform encountered JSON data that does not conform to the JSON specification. This commonly occurs in several scenarios: when using Terraform's `jsonencode()` function with improperly structured data, when embedding JSON strings directly in HCL, when using `jsondecode()` to parse invalid JSON, or when JSON is embedded in heredocs or local values. Terraform is strict about JSON validation because JSON-encoded data is often used in policies, configurations, and data passed to cloud providers. A single malformed JSON string can cause the entire apply to fail. The error message usually indicates the line and character position where the parser encountered the problem, though sometimes this requires careful reading of the error output. Common culprits include trailing commas (valid in HCL but not JSON), unquoted keys or values, improper escaping of quotes, control characters in strings, and BOM (Byte Order Mark) characters at the start of files.

Typical symptoms

  • Terraform plan or apply fails with 'Invalid JSON syntax' error
  • Error message includes a line/character position but it's unclear what's wrong
  • JSON validation passes in online tools but fails in Terraform
  • The error appears when using jsonencode() function
  • Heredoc-embedded JSON fails validation
  • Error occurs when parsing JSON from external files or templates
  • Works locally with terraform console but fails in plan

Common causes

  1. Trailing commas in JSON objects or arrays (valid in HCL, invalid in JSON)
  2. Unquoted string keys or values in JSON (JSON requires all keys and strings to be quoted)
  3. Mismatched or misquoted quote characters in JSON strings
  4. Improper escaping of special characters like quotes, backslashes, or newlines
  5. Mixing tabs or inconsistent indentation in JSON heredocs
  6. BOM (Byte Order Mark) or other invisible characters at the start of JSON data
  7. Using HCL comments inside JSON-encoded data
  8. Improperly escaped newlines or special Unicode characters
  9. Data types that are valid in HCL but invalid in JSON (e.g., null vs null string)

How to fix "Error: Invalid JSON syntax"

1Identify the exact JSON causing the error

First, identify where the JSON is coming from. Check the Terraform error message for file location and line number:

bash
Error: Invalid JSON syntax: ...
  on main.tf line 42, in resource "aws_iam_role_policy" "example":
   42:   policy = jsonencode({

The error usually points to where the jsonencode() call or JSON string starts. Look at that specific location in your configuration.

2Check for trailing commas

Trailing commas are allowed in HCL but forbidden in JSON. This is a very common cause:

Wrong - trailing comma in JSON:

hcl
policy = jsonencode({
  Version = "2012-10-17",
  Statement = [
    {
      Effect = "Allow",
      Action = "s3:GetObject",  # This comma is fine in HCL
    },  # But a trailing comma here is NOT allowed in JSON!
  ],
})

Correct - no trailing comma:

hcl
policy = jsonencode({
  Version = "2012-10-17",
  Statement = [
    {
      Effect = "Allow",
      Action = "s3:GetObject"  # No comma after the last item
    }
  ]
})

This is the single most common cause of "Invalid JSON syntax" errors. Even though HCL allows trailing commas for convenience, jsonencode() produces strict JSON.

3Verify all JSON keys and strings are properly quoted

JSON requires all keys and string values to be enclosed in double quotes. HCL is more flexible:

Wrong - unquoted keys in JSON:

hcl
value = jsonencode({
  name: "John",      # Keys must be quoted in JSON
  age: 30            # Bare numbers are fine, but keys aren't
})

Correct - quoted keys:

hcl
value = jsonencode({
  "name" = "John",   # Keys are quoted (using = not :)
  "age" = 30         # Numbers don't need quotes
})

In HCL using jsonencode(), use this syntax:
- Use = for key-value pairs (not :)
- Quote keys and string values: "key" = "value"
- Don't quote numbers or booleans: "count" = 5, "active" = true

4Check quote escaping in JSON strings

When JSON is embedded in HCL strings, quotes must be properly escaped. Use jsonencode() to avoid manual escaping:

Wrong - improper escaping:

hcl
# Dangerous and error-prone
policy = "{\"Version\": \"2012-10-17\", \"Statement\": [...]}"

Correct - use jsonencode():

hcl
# Let Terraform handle the escaping
policy = jsonencode({
  Version = "2012-10-17",
  Statement = [...]
})

If you must use raw JSON strings, use a heredoc:

hcl
policy = <<-EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*"
    }
  ]
}
EOF

The heredoc preserves the literal JSON without HCL escaping requirements.

5Validate JSON syntax using terraform console

Use terraform console to test jsonencode() expressions in isolation:

bash
# Start interactive console
terraform console

# Test your jsonencode expression
> jsonencode({
    "name" = "test",
    "value" = 123
  })
"{"name":"test","value":123}"

# Test jsondecode to verify it's valid
> jsondecode(jsonencode({
    "name" = "test"
  }))
{
  "name" = "test"
}

If terraform console works but your configuration doesn't, look for differences in the surrounding context.

Exit the console by pressing Ctrl+C or Ctrl+D.

6Validate standalone JSON files

If you're loading JSON from external files, validate them separately:

bash
# Validate JSON syntax using jq (if installed)
jq . policy.json

# Or using Python
python3 -m json.tool policy.json

# Using Node.js
node -e "console.log(JSON.parse(require('fs').readFileSync('policy.json')))"

All of these tools will report exactly where the JSON is invalid. If they pass, the issue may be with how Terraform is reading the file.

For Terraform:

hcl
# Load and parse JSON from file
policy = file("${path.module}/policy.json")

# Or parse it if it's stored as a JSON string
parsed_data = jsondecode(file("${path.module}/data.json"))
7Check for invisible characters and encoding issues

Sometimes JSON fails due to invisible characters like BOM, tabs, or Unicode characters:

bash
# Check file encoding (should be UTF-8)
file policy.json

# Look for BOM at the start
hexdump -C policy.json | head -1
# BOM appears as: ef bb bf

# Check for tabs vs spaces
cat -A policy.json
# Tabs appear as ^I, spaces as regular spaces

Common issues:
- BOM (Byte Order Mark): Some editors add UTF-8 BOM. Delete it in your editor.
- Mixed tabs/spaces: JSON is sensitive to indentation. Use consistent spaces (not tabs).
- Control characters: Remove any non-printable characters.
- Smart quotes: Copy-pasting from word processors sometimes converts " to " or "

In your Terraform configuration, if JSON comes from a file, ensure it's saved as UTF-8 without BOM.

8Verify data types in jsonencode()

JSON has specific data types. Ensure your HCL data matches JSON expectations:

Valid JSON types:

hcl
jsonencode({
  "string"   = "text",           # Strings (quoted)
  "number"   = 42,               # Numbers (no quotes)
  "float"    = 3.14,             # Floats (no quotes)
  "boolean"  = true,             # Booleans: true/false (lowercase, no quotes)
  "null"     = null,             # Null value
  "array"    = [1, 2, 3],        # Arrays
  "object"   = { "key" = "val" } # Objects
})

Invalid:

hcl
# These will cause issues
jsonencode({
  "undefined" = undefined,       # HCL feature, not valid in JSON
  "single"    = 'quoted',        # JSON requires double quotes, not single
  "unquoted"  = unquoted_value   # Must be quoted or be null/true/false/number
})

If you need to handle null or optional values in HCL before encoding:

hcl
locals {
  policy = jsonencode({
    "optional_field" = var.some_field != null ? var.some_field : "default"
  })
}
9Use jsondecode() to validate external JSON

If Terraform is giving you a generic "Invalid JSON syntax" error, wrap the JSON in jsondecode() to get a better error message:

Before - vague error:

hcl
policy = file("${path.module}/policy.json")  # Might fail silently

Better - explicit validation:

hcl
# This will immediately fail if policy.json is invalid JSON
policy = jsonencode(jsondecode(file("${path.module}/policy.json")))

jsondecode() provides more specific error messages that pinpoint the exact problem in your JSON file.

Once you've fixed the JSON, you can remove the outer jsonencode() wrapper:

hcl
policy = file("${path.module}/policy.json")

Advanced notes

HCL vs JSON syntax: Terraform accepts both HCL and JSON (.tf.json) files. HCL is more forgiving (allows unquoted keys, trailing commas, comments), while JSON is strict. When using jsonencode(), you're converting HCL data to strict JSON. This is why HCL syntax that works in .tf files causes errors when jsonencoded.

Large policy documents: For complex IAM or resource policies, store them in separate .json files rather than embedding them in HCL:

hcl
# main.tf
resource "aws_iam_role_policy" "example" {
  role   = aws_iam_role.example.name
  policy = file("${path.module}/policies/policy.json")
}

This approach is cleaner and allows you to validate JSON independently.

Template strings and interpolation: When using template strings with JSON, be careful with interpolation:

hcl
# Correct - interpolate inside jsonencode
policy = jsonencode({
  "resource" = "arn:aws:s3:::${aws_s3_bucket.example.id}"
})

# Problematic - raw string with interpolation
policy = "{ \"resource\": \"arn:aws:s3:::${aws_s3_bucket.example.id}\" }"

Terraform version considerations: Terraform 0.12+ handles JSON strictly. Older versions may have more lenient parsing. Always upgrade to a supported version.

Debugging output: Use terraform console or terraform output to inspect the actual JSON string being generated before Terraform fails on it:

bash
terraform console
> base64encode(var.json_policy)  # See exact bytes

Frequently asked questions

What does "Error: Invalid JSON syntax" mean?
The "Invalid JSON syntax" error indicates that Terraform encountered JSON data that does not conform to the JSON specification. This commonly occurs in several scenarios: when using Terraform's jsonencode() function with improperly structured data, when embedding JSON strings directly in HCL, when using jsondecode() to parse invalid JSON, or when JSON is embedded in heredocs or local values. Terraform is strict about JSON validation because JSON-encoded data is often used in policies, configurations, and data passed to cloud providers.
How do I fix "Error: Invalid JSON syntax"?
This error occurs when Terraform detects malformed JSON in your configuration, typically in JSON-encoded strings, heredocs, or when mixing HCL with inline JSON. JSON requires proper structure with quoted keys, commas, and no trailing commas.
What causes "Error: Invalid JSON syntax"?
Trailing commas in JSON objects or arrays (valid in HCL, invalid in JSON) Unquoted string keys or values in JSON (JSON requires all keys and strings to be quoted) Mismatched or misquoted quote characters in JSON strings
Is the "Error: Invalid JSON syntax" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading