Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for OpenTofu By James Joyner IV · · 8 min read

OpenTofu Error: 'Error loading state: AccessDenied' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix OpenTofu 'Error loading state: ... AccessDenied' from missing IAM permissions, wrong bucket/region, expired credentials, or KMS denials.

  • #opentofu
  • #iac
  • #troubleshooting
  • #errors
Free toolkit

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/apply fails with Error 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:GenerateDataKey on 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, and kms:Decrypt need 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.
Free download · 368-page PDF

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.