This error occurs when a Terraform external data source invokes a program that doesn't return properly formatted JSON. The external program must output a flat JSON object with string keys and string values to stdout.
The external data source in Terraform runs an external program and expects it to return valid JSON on stdout. This error indicates the program's output doesn't conform to Terraform's strict JSON requirements: it must be a flat object (no nested objects or arrays), all values must be strings, and the syntax must be valid JSON with proper quoting.
Use an online JSON validator (like JSONLint) or a command-line tool to check your program's output:
# Run your external program and pipe to a JSON validator
your_program | jq empty
# If jq fails, your JSON is invalidThis will immediately show you syntax errors like trailing commas, missing quotes, or unclosed brackets.
Modify your external program to output a flat JSON object with only string values:
# WRONG - returns Python dict with single quotes
result = {"ip": "10.190.170.37", "network": "10.190.170.0"}
print(result)
# CORRECT - proper JSON with double quotes
import json
result = {"ip": "10.190.170.37", "network": "10.190.170.0"}
print(json.dumps(result))Ensure:
- All keys and string values use double quotes
- No nested objects or arrays
- All values are strings (convert numbers/booleans to strings if needed)
If writing shell scripts, use jq to safely construct JSON:
#!/bin/bash
ip="10.190.170.37"
network="10.190.170.0"
# Safe JSON construction with jq
jq -n --arg ip "$ip" --arg network "$network" \
'{"ip": $ip, "network": $network}'This prevents accidental JSON syntax errors from string interpolation.
Check that your program only outputs JSON to stdout:
import json
import sys
# DON'T DO THIS - debug output breaks JSON
print("Starting script...") # This breaks the JSON!
result = {"key": "value"}
print(json.dumps(result))
# DO THIS - only JSON to stdout
result = {"key": "value"}
print(json.dumps(result))
# Use stderr for debug output instead
print("Debug message", file=sys.stderr)All debug prints must go to stderr, not stdout.
Ensure your program exits with status code 0 on success:
# In bash
exit 0 # Success
# In Python
import sys
sys.exit(0) # Success
sys.exit(1) # FailureNon-zero exit codes cause Terraform to ignore the output and treat it as a program error.
Run your program outside of Terraform to verify it works:
# Test with the same inputs Terraform would use
echo '{"arg1": "value1"}' | your_program | jq .
# Check exit code
echo $?This isolates whether the problem is in your program or in how Terraform invokes it.
The external data source protocol has strict limitations by design: Terraform requires all values to be strings to maintain consistency with variable types. If you need to return complex data structures, serialize them as JSON strings within the flat object (e.g., {"data": "{\"nested\": \"value\"}"}), then parse them in your Terraform configuration with jsondecode(). For debugging, enable Terraform logging with TF_LOG=TRACE to see the exact program output and error details.
Error: Error installing helm release: cannot re-use a name that is still in use
How to fix "release name in use" error in Terraform with Helm
Error: Error creating GKE Cluster: BadRequest
BadRequest error creating GKE cluster in Terraform
Error: Unsupported argument in child module call
How to fix "Unsupported argument in child module call" in Terraform
Error: network is unreachable
How to fix "network is unreachable" in Terraform
Error: Error rendering template: template not found
How to fix "template not found" error in Terraform