OpenTofu Error: 'Error loading state: AccessDenied' — Cause, Fix, and Troubleshooting Guide
Fix OpenTofu 'Error loading state: ... AccessDenied' from missing IAM permissions, wrong bucket/region, expired credentials, or KMS denials.
- #opentofu
- #iac
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
Before any operation, OpenTofu reads the state object from your backend. If the identity running tofu lacks permission to read the bucket/object (or the KMS key that encrypts it), the backend returns AccessDenied and OpenTofu cannot load state:
Error: Error loading state:
AccessDenied: User: arn:aws:iam::111122223333:user/ci-deployer is not
authorized to perform: s3:GetObject on resource:
"arn:aws:s3:::example-tofu-state/prod/terraform.tfstate"
status code: 403, request id: 8F3...
Symptoms
tofu init/plan/applyfails withError loading state:and a 403 AccessDenied.- The message names the principal, the action (
s3:GetObject,s3:PutObject), and the resource. - Works with one profile/role but not another (CI vs local).
- May reference KMS (
kms:Decrypt) if the state bucket uses SSE-KMS.
Common Root Causes
- Missing IAM permissions on the state bucket/object or DynamoDB lock table.
- Wrong credentials/account — the identity can’t see the bucket.
- Expired or unassumed role in CI (OIDC/STS not configured).
- Wrong bucket or region in the backend config.
- KMS denial — no
kms:Decrypt/kms:GenerateDataKeyon the state encryption key.
How to diagnose
Confirm who you are and whether you can reach the bucket:
aws sts get-caller-identity
aws s3 ls s3://example-tofu-state/prod/ --region us-east-1
Read the exact denied action/resource from the error, then check the backend target:
grep -A8 'backend "s3"' *.tf
Test the specific object and the lock table:
aws s3api head-object --bucket example-tofu-state --key prod/terraform.tfstate
aws dynamodb describe-table --table-name tofu-locks >/dev/null && echo lock-ok
Fixes
Grant the required permissions to the principal (bucket read/write, lock table, KMS if used):
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::example-tofu-state",
"arn:aws:s3:::example-tofu-state/*"
]
}
Add lock-table and KMS permissions where applicable:
{ "Effect": "Allow",
"Action": ["dynamodb:GetItem","dynamodb:PutItem","dynamodb:DeleteItem"],
"Resource": "arn:aws:dynamodb:*:*:table/tofu-locks" }
Assume the right role / refresh credentials before running:
export AWS_PROFILE=deployer
aws sts get-caller-identity # confirm the expected account
Correct the backend target if bucket or region is wrong:
backend "s3" {
bucket = "example-tofu-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
What to watch out for
- Read the denied action in the message —
GetObject,PutObject,ListBucket, andkms:Decryptneed distinct grants. - CI usually fails here because OIDC/role assumption is misconfigured, not because the config is wrong.
- SSE-KMS state buckets require KMS key permissions in addition to S3 permissions.
- A wrong region silently points at a non-existent object and looks like a permission error.
Related
- OpenTofu Error: ‘Error acquiring the state lock’ — Cause, Fix, and Troubleshooting Guide
- OpenTofu Error: ‘decryption failed’ — Cause, Fix, and Troubleshooting Guide
- OpenTofu Error: ‘Backend configuration changed’ — Cause, Fix, and Troubleshooting Guide
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.