TerraformPilot

Cloud Computing

Terraform Debug Mode: How to Enable TF_LOG and Read Debug Output

Enable Terraform debug mode with TF_LOG=DEBUG, save logs to file with TF_LOG_PATH, and troubleshoot terraform plan/apply errors.

LLuca Berton4 min read

Introduction

#

When terraform plan or terraform apply fails with a cryptic error, you need debug output. Terraform's built-in debugging system uses environment variables to control log verbosity — no code changes required.

This guide covers everything you need to debug Terraform: enabling TF_LOG, choosing the right log level, saving output to files, and reading debug logs to find the actual problem.

Quick Start: Enable Terraform Debug Mode

#

The fastest way to get debug output:

# Linux/macOS
export TF_LOG=DEBUG
terraform plan
 
# Windows PowerShell
$env:TF_LOG = "DEBUG"
terraform plan
 
# Windows CMD
set TF_LOG=DEBUG
terraform plan

To turn it off:

# Linux/macOS
unset TF_LOG
 
# Windows PowerShell
$env:TF_LOG = ""

TF_LOG Levels Explained

#

Terraform supports 5 log levels, from most verbose to least:

LevelWhat It ShowsWhen to Use
TRACEEvery internal operation, API calls, HTTP requests/responses, provider plugin communicationDeep debugging, provider issues
DEBUGResource diffs, state operations, dependency graphMost debugging scenarios
INFOHigh-level operational messagesGeneral monitoring
WARNPotential problems that don't cause failuresReviewing configuration health
ERROROnly errors that stop executionFiltering noise in large runs

TRACE Level

#

TRACE is the most verbose level. It shows everything including raw HTTP requests to cloud provider APIs:

export TF_LOG=TRACE
terraform plan

Example TRACE output:

2024-02-07T10:15:32.456Z [TRACE] provider.terraform-provider-aws: Calling AWS API: ec2:DescribeInstances
2024-02-07T10:15:32.789Z [TRACE] provider.terraform-provider-aws: HTTP Request: GET https://ec2.us-east-1.amazonaws.com/?Action=DescribeInstances
2024-02-07T10:15:33.123Z [TRACE] provider.terraform-provider-aws: HTTP Response: 200 OK

Use TRACE when you suspect the provider is making incorrect API calls or when you need to see exactly what Terraform sends to the cloud.

DEBUG Level

#

DEBUG is the most commonly used level. It shows resource changes, state operations, and the dependency graph without the noise of raw HTTP traffic:

export TF_LOG=DEBUG
terraform apply

Example DEBUG output:

2024-02-07T10:15:32.456Z [DEBUG] provider: planning resource change: resource=aws_instance.web
2024-02-07T10:15:32.789Z [DEBUG] provider: diff result: attribute=instance_type old="t2.micro" new="t3.micro"

This is your go-to level for most debugging.

Save Debug Output to a File with TF_LOG_PATH

#

Console output scrolls fast. Save it to a file for easier analysis:

# Save all debug output to a file
export TF_LOG=DEBUG
export TF_LOG_PATH=./terraform-debug.log
terraform plan

The file captures all Terraform output. You can then search it:

# Find errors
grep "ERROR" terraform-debug.log
 
# Find API calls
grep "HTTP" terraform-debug.log
 
# Find a specific resource
grep "aws_instance" terraform-debug.log

Important: TF_LOG_PATH only works when TF_LOG is also set. The file is overwritten on each run — rename or move it if you want to keep it.

Separate Provider Logs

#

Since Terraform 0.15, you can set log levels separately for Terraform core and providers:

# Terraform core at INFO, providers at TRACE
export TF_LOG_CORE=INFO
export TF_LOG_PROVIDER=TRACE
terraform plan

This is useful when you know the issue is in a provider (like the AWS or Azure provider) and don't want noise from Terraform's core operations.

Debug Specific Terraform Commands

#

Debug terraform init

#
export TF_LOG=DEBUG
terraform init

Common issues init debug logs reveal:

  • Provider download failures (network/proxy issues)
  • Registry authentication errors
  • Backend configuration problems
  • Module source resolution failures

Debug terraform plan

#
export TF_LOG=DEBUG
terraform plan

Look for:

  • State refresh failures (resource not found)
  • Provider credential errors
  • Resource dependency ordering issues
  • Variable interpolation problems

Debug terraform apply

#
export TF_LOG=DEBUG
terraform apply

Watch for:

  • API rate limiting (429 responses in TRACE mode)
  • Resource creation timeouts
  • Dependency ordering failures
  • State locking conflicts

Common Debugging Scenarios

#

Authentication Errors

#

If you see InvalidClientTokenId or AuthFailure:

export TF_LOG=TRACE
terraform plan 2>&1 | grep -i "auth\|credential\|token\|403\|401"

Check that your credentials are set:

# AWS
aws sts get-caller-identity
 
# Azure
az account show
 
# GCP
gcloud auth application-default print-access-token

Provider Plugin Crashes

#

When a provider crashes, enable TRACE to see the plugin communication:

export TF_LOG=TRACE
export TF_LOG_PATH=./crash-debug.log
terraform plan
 
# Look for the crash
grep -A5 "plugin" crash-debug.log

State Lock Issues

#
export TF_LOG=DEBUG
terraform plan 2>&1 | grep -i "lock\|state"

If the state is locked, you'll see the lock ID. Force unlock with:

terraform force-unlock LOCK_ID

Slow Operations

#

Use TRACE to find which API calls are slow:

export TF_LOG=TRACE
export TF_LOG_PATH=./slow-debug.log
terraform plan
 
# Find slow operations (look at timestamps)
grep "HTTP Response" slow-debug.log | sort -k1

Debug in CI/CD Pipelines

#

GitLab CI

#
terraform_plan:
  script:
    - export TF_LOG=DEBUG
    - export TF_LOG_PATH=./terraform-debug.log
    - terraform plan -out=tfplan
  artifacts:
    paths:
      - terraform-debug.log
    when: on_failure

GitHub Actions

#
- name: Terraform Plan
  env:
    TF_LOG: DEBUG
    TF_LOG_PATH: ./terraform-debug.log
  run: terraform plan -out=tfplan
 
- name: Upload Debug Logs
  if: failure()
  uses: actions/upload-artifact@v4
  with:
    name: terraform-debug-logs
    path: terraform-debug.log

Environment Variable Reference

#
VariableValuesDescription
TF_LOGTRACE, DEBUG, INFO, WARN, ERRORSet log level for all components
TF_LOG_CORESame as TF_LOGSet log level for Terraform core only
TF_LOG_PROVIDERSame as TF_LOGSet log level for providers only
TF_LOG_PATHFile pathWrite logs to file instead of stderr

Best Practices

#
  1. Start with DEBUG, escalate to TRACE: DEBUG covers 90% of issues. Only use TRACE when you need API-level detail.
  2. Always save to file: Debug output is massive. Use TF_LOG_PATH so you can search it.
  3. Sanitize before sharing: Logs may contain credentials, account IDs, or resource details. Scrub them before posting to GitHub Issues or forums.
  4. Disable after debugging: Debug logging slows Terraform and creates large files. Always unset TF_LOG when done.
  5. Use provider-specific logging: TF_LOG_CORE and TF_LOG_PROVIDER let you focus on the relevant component.
  6. Version your state: If debugging a state issue, back up .terraform.tfstate before making changes.

Hands-On Courses

#

Learn by doing with interactive courses on CopyPasteLearn:

Conclusion

#

Terraform debug mode is your most powerful troubleshooting tool. Set TF_LOG=DEBUG to see what Terraform is actually doing, use TF_LOG_PATH to save output for analysis, and use TRACE when you need to see raw API calls. Combined with TF_LOG_CORE and TF_LOG_PROVIDER for targeted debugging, you can quickly diagnose any Terraform issue from authentication failures to provider crashes.

#Terraform#HashiCorp#DevOps#Infrastructure as Code#Troubleshooting#TF_LOG#Debugging

Share this article