How to fix Error: Provisioner execution failed - exit status 1 in Terraform

TerraformINTERMEDIATEHIGHUpdated Dec 31, 2025ยท 127 views

A Terraform provisioner (local-exec or remote-exec) executed a command that failed with exit status 1. This occurs when the underlying script or command returns a non-zero exit code, causing the provisioner to fail and mark the resource as tainted.

Quick fix

Fixes Error: Provisioner execution failed - exit status 1

# Linux/macOS
export TF_LOG=DEBUG
terraform apply 2>&1 | tee terraform.log

# Windows (PowerShell)
$env:TF_LOG="DEBUG"
terraform apply | Tee-Object -FilePath terraform.log
  1. Add verbose logging to your provisioner
  2. Test your provisioner command independently
  3. Fix remote-exec inline arrays with 'set -e'
  4. Verify file paths and permissions
terraform โ€” error
# Linux/macOS
export TF_LOG=DEBUG
terraform apply 2>&1 | tee terraform.log
# Windows (PowerShell)
$env:TF_LOG="DEBUG"
terraform apply | Tee-Object -FilePath terraform.log
Error: Provisioner execution failed - exit status 1

What this error means

Exit status 1 is a generic non-zero exit code that indicates command failure. When Terraform runs a provisioner, it captures the exit code of the executed command. Any non-zero exit status (like 1) causes Terraform to consider the provisioner failed. By default, this failure marks the resource as tainted, requiring it to be destroyed and recreated on the next terraform apply. The error message often masks the actual command failure, making root cause diagnosis difficult.

Typical symptoms

  • terraform apply stops with 'Provisioner execution failed - exit status 1'
  • Resource becomes marked as tainted after provisioner fails
  • terraform plan shows the resource will be destroyed and recreated
  • No clear indication of which command in the provisioner actually failed
  • Provisioner output is truncated or missing detailed error messages

Common causes

  1. The provisioned command or script encountered an error and exited with code 1
  2. A command in a remote-exec inline array failed but execution continued to the final command
  3. File path errors (source file missing, incorrect destination path, or permission denied)
  4. SSH/WinRM connection issues preventing command execution on remote resources
  5. Missing dependencies or tools required by the provisioned command on the target system
  6. Inadequate permissions for the command being executed (EACCES errors)
  7. Network timeout or connectivity loss during remote-exec provisioner execution

How to fix "Error: Provisioner execution failed - exit status 1"

1Add verbose logging to your provisioner

Enable Terraform debug logging to see more detailed error output:

bash
# Linux/macOS
export TF_LOG=DEBUG
terraform apply 2>&1 | tee terraform.log

# Windows (PowerShell)
$env:TF_LOG="DEBUG"
terraform apply | Tee-Object -FilePath terraform.log

Review the log file to find the actual error message before the exit status 1.

2Test your provisioner command independently

Run the exact command outside of Terraform to identify the failure:

For local-exec:

bash
# Test your command directly
/path/to/your/script.sh
echo "Exit code: $?"

For remote-exec, SSH to the remote instance and run the command:

bash
ssh -i /path/to/key.pem user@remote-host
# Then run your command
your-command-here

This reveals the actual error instead of Terraform's generic exit status message.

3Fix remote-exec inline arrays with 'set -e'

By default, inline commands execute independently. Add set -e to stop on first error:

Before (stops at last command only):

hcl
provisioner "remote-exec" {
  inline = [
    "apt-get update",
    "apt-get install nginx",
    "systemctl start nginx"
  ]
}

After (stops at first error):

hcl
provisioner "remote-exec" {
  inline = [
    "set -e",
    "apt-get update",
    "apt-get install nginx",
    "systemctl start nginx"
  ]
}

The set -e flag causes the script to exit immediately if any command returns non-zero.

4Verify file paths and permissions

For file provisioners, ensure paths exist and permissions are correct:

hcl
# Verify source file exists before provisioning
provisioner "file" {
  source      = "${path.module}/scripts/deploy.sh"  # Use path.module for relative paths
  destination = "/tmp/deploy.sh"

  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file(var.private_key_path)
    host        = aws_instance.example.public_ip
  }
}

# Make script executable
provisioner "remote-exec" {
  inline = [
    "set -e",
    "chmod +x /tmp/deploy.sh",
    "/tmp/deploy.sh"
  ]

  connection {
    type        = "ssh"
    user        = "ubuntu"
    private_key = file(var.private_key_path)
    host        = aws_instance.example.public_ip
  }
}
5Use 'on_failure = continue' if the failure is acceptable

If the provisioner failure isn't critical, allow Terraform to continue:

hcl
provisioner "local-exec" {
  command    = "curl http://example.com/webhook || true"  # || true prevents exit 1
  on_failure = continue  # Don't taint resource if provisioner fails
}

Or use || true in your command to return exit code 0 even if the command fails.

Note: Use this sparingly. If the provisioner is critical, fix the underlying issue instead.

6Check SSH/WinRM connectivity for remote-exec

If using remote-exec, verify the connection works:

bash
# Test SSH connection
ssh -i /path/to/key.pem -v user@remote-host echo "Connected"

# If using WinRM on Windows instances
# Test with: powershell -Command "Test-WSMan -ComputerName remote-host -ErrorAction SilentlyContinue"

Common remote-exec connection issues:
- Security group doesn't allow SSH (port 22) or WinRM (port 5985/5986)
- Instance still initializing (add depends_on or waiter)
- Incorrect username for the AMI (ubuntu, ec2-user, admin, etc.)
- Private key file permissions too open (chmod 600 on Unix)

Advanced notes

Why provisioners are discouraged:

HashiCorp recommends treating provisioners as a last resort because they:
1. Make infrastructure less reproducible (different results on retry)
2. Hide implicit dependencies not shown in Terraform graph
3. Create coupling between Terraform and external tools

Better alternatives:
- User data scripts: Use user_data or user_data_base64 on cloud instances
- Cloud-init: Pass initialization via cloudinit_config data source
- Configuration management: Use Ansible, Chef, Puppet, or SaltStack
- Container images: Bake configuration into AMIs or Docker images via Packer
- CI/CD integration: Trigger post-Terraform deployments via pipelines

Debugging provisioner issues:
- Set TF_LOG=DEBUG environment variable for verbose output
- Check CloudWatch logs or system logs on remote instances
- Test commands manually before adding to provisioners
- Use connection blocks to specify SSH/WinRM details explicitly
- Consider using on_failure = continue only as temporary workaround

Frequently asked questions

What does "Error: Provisioner execution failed - exit status 1" mean?
Exit status 1 is a generic non-zero exit code that indicates command failure. When Terraform runs a provisioner, it captures the exit code of the executed command. Any non-zero exit status (like 1) causes Terraform to consider the provisioner failed.
How do I fix "Error: Provisioner execution failed - exit status 1"?
A Terraform provisioner (local-exec or remote-exec) executed a command that failed with exit status 1. This occurs when the underlying script or command returns a non-zero exit code, causing the provisioner to fail and mark the resource as tainted.
What causes "Error: Provisioner execution failed - exit status 1"?
The provisioned command or script encountered an error and exited with code 1 A command in a remote-exec inline array failed but execution continued to the final command File path errors (source file missing, incorrect destination path, or permission denied)
Is the "Error: Provisioner execution failed - exit status 1" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading