hashicorp/terraform · error

failed to access object '%s' in bucket '%s': %w

Error message

failed to access object '%s' in bucket '%s': %w

What it means

Raised in RemoteClient.getObject when the OCI HeadObject call fails with an error that is NOT a 404 (the 404 branch treats a missing state file as a normal initialization and returns an empty payload). It wraps the raw SDK error along with the configured object path and bucket name so the practitioner can see which state file could not be inspected. Any HeadObject failure other than NotNotFound surfaces here: auth, authorization, throttling, server faults, network, or a wrong namespace/bucket.

Source

Thrown at internal/backend/remote-state/oci/client.go:74

		BucketName:    common.String(c.bucketName),
		RequestMetadata: common.RequestMetadata{
			RetryPolicy: getDefaultRetryPolicy(),
		},
	}
	if c.SSECustomerKey != "" && c.SSECustomerKeySHA256 != "" {
		headRequest.OpcSseCustomerKey = common.String(c.SSECustomerKey)
		headRequest.OpcSseCustomerKeySha256 = common.String(c.SSECustomerKeySHA256)
		headRequest.OpcSseCustomerAlgorithm = common.String(c.SSECustomerAlgorithm)
	}
	// Get object from OCI
	headResponse, headErr := c.objectStorageClient.HeadObject(ctx, headRequest)
	if headErr != nil {
		var ociHeadErr common.ServiceError
		if errors.As(headErr, &ociHeadErr) && ociHeadErr.GetHTTPStatusCode() == 404 {
			logger.Debug(" State file '%s' not found. Initializing Terraform state...", c.path)
			return &remote.Payload{}, nil
		} else {
			return nil, fmt.Errorf("failed to access object '%s' in bucket '%s': %w", c.path, c.bucketName, headErr)
		}
	}

	getRequest := objectstorage.GetObjectRequest{
		NamespaceName: common.String(c.namespace),
		ObjectName:    common.String(c.path),
		BucketName:    common.String(c.bucketName),
		IfMatch:       headResponse.ETag,
		RequestMetadata: common.RequestMetadata{
			RetryPolicy: getDefaultRetryPolicy(),
		},
	}
	if c.SSECustomerKey != "" && c.SSECustomerKeySHA256 != "" {
		getRequest.OpcSseCustomerKey = common.String(c.SSECustomerKey)
		getRequest.OpcSseCustomerKeySha256 = common.String(c.SSECustomerKeySHA256)
		getRequest.OpcSseCustomerAlgorithm = common.String(c.SSECustomerAlgorithm)
	}
	// Get object from OCI

View on GitHub (pinned to c9def3e214)

Solutions

  1. Verify the backend 'bucket', 'namespace', and 'key'/'prefix' values match an existing bucket and object path using 'oci os object head --bucket-name <b> --namespace <ns> --name <key>'.
  2. Confirm the IAM principal Terraform runs as has OBJECT_INSPECT + OBJECT_READ on the bucket and OBJECT_CREATE/OBJECT_OVERWRITE for writes (check the policy and any dynamic group).
  3. Re-authenticate or refresh credentials: run 'oci session refresh' (or re-export OCI_AUTH/OCI_SESSION_TOKEN) when using instance/principal delegation token auth that has expired.
  4. If intermittent, rely on the SDK retry policy (getDefaultRetryPolicy) and re-run 'terraform init'/'terraform plan'; for sustained 429s request a service-limit increase.
  5. Enable OCI request logging and confirm the resolved region/tenancy; a wrong region yields authorization-style failures even with valid credentials.

Example fix

# before (wrong namespace)
terraform {
  backend "oci" {
    namespace = "idexample"   # typo
    bucket   = "tf-state"
    key      = "prod/terraform.tfstate"
  }
}
# after (correct namespace from 'oci os ns get')
terraform {
  backend "oci" {
    namespace = "idxxxxxxxxxxx"
    bucket   = "tf-state"
    key      = "prod/terraform.tfstate"
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// Before init/plan, confirm head reachability and permissions with the OCI CLI:
//   oci os bucket get --namespace <ns> --name <bucket>
//   oci os object head --namespace <ns> --bucket-name <bucket> --name <key>
// In Go, validate config before constructing the backend:
if c.namespace == "" || c.bucketName == "" || c.path == "" {
    return fmt.Errorf("oci backend requires namespace, bucket and key to be set")
}

Type guard

// Distinguish 404 (legitimate empty init) from other head failures:
var ociErr common.ServiceError
if errors.As(err, &ociErr) && ociErr.GetHTTPStatusCode() == 404 {
    // object missing -> initialize fresh state
}

Try / catch

resp, err := c.objectStorageClient.HeadObject(ctx, headRequest)
if err != nil {
    var se common.ServiceError
    if errors.As(err, &se) && se.GetHTTPStatusCode() == 404 {
        return &remote.Payload{}, nil // expected: first run
    }
    return nil, fmt.Errorf("failed to access object '%s' in bucket '%s': %w", c.path, c.bucketName, err)
}

Prevention

When it happens

Trigger: A HeadObject request to objectstorage.ObjectStorageClient.HeadObject (client.go:67) returns a non-nil error that either is not a common.ServiceError or is a ServiceError whose HTTP status is not 404 (e.g. 401 NotAuthenticated, 404 on the bucket/namespace rather than the object, 403 NotAuthorizedOrNotFound, 429 TooManyRequests, 500/503).

Common situations: Wrong namespace or bucket name in the backend config; the IAM user lacks OBJECT_READ / READ on the bucket; OCID/region mismatch in the provider config; expired session token; OCI throttling the control plane; transient 5xx or network blip between Terraform and the object storage endpoint.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/023ed4c28180cf48. Report an issue: GitHub.