hashicorp/terraform · error

Unable to retrieve item from DynamoDB table

Error message

Unable to retrieve item from DynamoDB table %q: %w

What it means

Thrown by getMD5 when the DynamoDB GetItem that retrieves the stored state MD5 digest fails. The digest (stored under the LockID + stateIDSuffix key, Digest attribute) lets clients detect locally-cached stale state. A GetItem error here aborts the staleness check, which usually surfaces upstream as a state-read failure.

Solutions

  1. Verify the table exists and the name matches backend config: `aws dynamodb describe-table --table-name <table>` in the configured region/profile.
  2. Confirm dynamodb:GetItem permission on arn:aws:dynamodb:<region>:<acct>:table/<table> for the principal.
  3. If the table was recreated, update `dynamodb_table` to the new name; note the old digest rows become orphaned (harmless).
  4. For read throttling, switch to on-demand billing or raise read capacity, then retry.
  5. Temporarily removing `dynamodb_table` disables staleness tracking and lets state ops proceed while DDB is restored.

Example fix

# before: stale/missing ddb table name
backend "s3" {
  bucket         = "tf-state-prod"
  dynamodb_table = "terraform-locks-gone"
}
# after
backend "s3" {
  bucket         = "tf-state-prod"
  dynamodb_table = "terraform-locks"   # existing table
  region         = "us-west-2"
}
Defensive patterns

Strategy: retry

Validate before calling

// Before reading state, confirm the DDB digest table is reachable.
func ddbTableReachable(ctx context.Context, c *dynamodb.Client, table string) error {
  if _, err := c.DescribeTable(ctx, &dynamodb.DescribeTableInput{TableName: &table}); err != nil {
    return fmt.Errorf("dynamodb table %s not reachable: %w", table, err)
  }
  return nil
}

Try / catch

// Retry transient GetItem; fail fast on ResourceNotFound/AccessDenied.
for i := 0; i < 3; i++ {
  resp, err := c.dynClient.GetItem(ctx, getParams)
  if err == nil { /* process resp */ return sum, nil }
  var apiErr smithy.APIError
  if errors.As(err, &apiErr) {
    if apiErr.ErrorCode() == "ResourceNotFoundException" || apiErr.ErrorCode() == "AccessDenied" {
      return nil, fmt.Errorf("Unable to retrieve item from DynamoDB table %q: %w", c.ddbTable, err)
    }
  }
  time.Sleep(backoff(i))
}

Prevention

When it happens

Trigger: c.dynClient.GetItem at client.go:607 returns an error. Triggers: dynamodb_table configured but the table was deleted/renamed, IAM principal lacks dynamodb:GetItem, region/account mismatch, table throttled on read capacity, or a resource-based policy denying the principal.

Common situations: DynamoDB lock table recreated without updating backend config, cross-account role missing DDB read perms, switched AWS profile so the table is unreachable, or heavy concurrent reads exhausting provisioned read capacity.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/890d28cacf81ac7c. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/s3/client.go:609

func (c *RemoteClient) getMD5(ctx context.Context) ([]byte, error) {
	if c.ddbTable == "" {
		return nil, nil
	}

	getParams := &dynamodb.GetItemInput{
		Key: map[string]dynamodbtypes.AttributeValue{
			"LockID": &dynamodbtypes.AttributeValueMemberS{
				Value: c.lockPath() + stateIDSuffix,
			},
		},
		ProjectionExpression: aws.String("LockID, Digest"),
		TableName:            aws.String(c.ddbTable),
		ConsistentRead:       aws.Bool(true),
	}

	resp, err := c.dynClient.GetItem(ctx, getParams)
	if err != nil {
		return nil, fmt.Errorf("Unable to retrieve item from DynamoDB table %q: %w", c.ddbTable, err)
	}

	var val string
	if v, ok := resp.Item["Digest"]; ok {
		if v, ok := v.(*dynamodbtypes.AttributeValueMemberS); ok {
			val = v.Value
		}
	}

	sum, err := hex.DecodeString(val)
	if err != nil || len(sum) != md5.Size {
		return nil, errors.New("invalid md5")
	}

	return sum, nil
}

// store the hash of the state so that clients can check for stale state files.

View on GitHub (pinned to d32a084675)