hashicorp/terraform · error

failed to access object HttpStatusCode: %d OpcRequestId: %s

Error message

failed to access object HttpStatusCode: %d
OpcRequestId: %s
 message: %s
 ErrorCode: %s

What it means

Raised in getObject after HeadObject succeeded but the follow-up GetObject call failed with an error that the OCI SDK recognizes as a common.ServiceError. Unlike the generic wrap, this path unpacks the structured service error and prints the HTTP status code, the OpcRequestId (for Oracle support), the human-readable message, and the OCI ErrorCode, so the failure can be correlated server-side.

Source

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

		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
	getResponse, err := c.objectStorageClient.GetObject(ctx, getRequest)
	if err != nil {
		var ociErr common.ServiceError
		if errors.As(err, &ociErr) {
			return nil, fmt.Errorf("failed to access object HttpStatusCode: %d\nOpcRequestId: %s\n message: %s\n ErrorCode: %s", ociErr.GetHTTPStatusCode(), ociErr.GetOpcRequestID(), ociErr.GetMessage(), ociErr.GetCode())

		}
		return nil, fmt.Errorf("failed to access object '%s' in bucket '%s': %w", c.path, c.bucketName, err)
	}
	defer getResponse.Content.Close()

	// Read object content
	contentArray, err := io.ReadAll(getResponse.Content)
	if err != nil {
		return nil, fmt.Errorf("unable to read 'content' from response: %w", err)
	}

	// Compute MD5 hash
	md5Hash := getResponse.ContentMd5
	if md5Hash == nil || len(*md5Hash) == 0 {
		md5Hash = getResponse.OpcMultipartMd5
	}
	// Construct payload

View on GitHub (pinned to c9def3e214)

Solutions

  1. Read the printed OpcRequestId and ErrorCode: give the exact code+requestId to OCI support or grep the OCI console audit log to locate the server-side failure.
  2. For ErrorCode 412/PreconditionFailed or 'NotModified'/'Mismatch': re-run the operation; another process is mutating the state and the ETag-based IfMatch guard rejected the stale read.
  3. For SSE-C errors confirm the opc-sse-customer-key / -sha256 / -algorithm backend attributes match the key that encrypted the object; a wrong key yields a decryption ServiceError.
  4. For 429/5xx codes the retry policy already retries idempotent GETs; if it still bubbles up, throttle parallel Terraform runs and retry after a short backoff.
  5. For 401/403 verify the IAM policy grants OBJECT_READ on the bucket for the running principal.

Example fix

// before: stale ETag from a long gap between head and get
getResponse, err := c.objectStorageClient.GetObject(ctx, getRequest)
if err != nil {
    return nil, fmt.Errorf("failed to access object HttpStatusCode: %d\n...", ociErr.GetHTTPStatusCode(), ...)
}
// after: drop IfMatch for a best-effort read (accepts whatever is current)
getRequest := objectstorage.GetObjectRequest{
    NamespaceName: common.String(c.namespace),
    ObjectName:    common.String(c.path),
    BucketName:    common.String(c.bucketName),
    RequestMetadata: common.RequestMetadata{RetryPolicy: getDefaultRetryPolicy()},
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate the ETag you intend to pass as IfMatch is fresh (within the same op):
headResp, _ := c.objectStorageClient.HeadObject(ctx, headRequest)
if headResp.ETag == nil { return fmt.Errorf("no ETag from head; cannot safely IfMatch GET") }

Type guard

var se common.ServiceError
if errors.As(err, &se) {
    // se.GetHTTPStatusCode(), se.GetOpcRequestID(), se.GetMessage(), se.GetCode()
    switch se.GetHTTPStatusCode() {
    case 412: // precondition failed (etag mismatch)
    case 429: // throttled
    case 401, 403: // auth/authorization
    }
}

Try / catch

getResponse, err := c.objectStorageClient.GetObject(ctx, getRequest)
if err != nil {
    var se common.ServiceError
    if errors.As(err, &se) {
        return nil, fmt.Errorf("failed to access object HttpStatusCode: %d\nOpcRequestId: %s\n message: %s\n ErrorCode: %s",
            se.GetHTTPStatusCode(), se.GetOpcRequestID(), se.GetMessage(), se.GetCode())
    }
    return nil, fmt.Errorf("failed to access object '%s' in bucket '%s': %w", c.path, c.bucketName, err)
}

Prevention

When it happens

Trigger: GetObject (client.go:93) returns an error for which errors.As(err, &ociErr) succeeds. Typical codes: 412 PreconditionFailed when IfMatch (headResponse.ETag at client.go:82) no longer matches (the object changed between head and get), 403, 401, 429, or a 5xx from the object storage service.

Common situations: Two processes writing the same state concurrently so the ETag changes between Head and Get; SSE-Customer-Key mismatch (wrong key/algo) causing the GET to fail decryption; throttling on a busy bucket; an object that was deleted or overwritten in the ~milliseconds between Head and Get; transient service degradation.

Related errors


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