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 payloadView on GitHub (pinned to c9def3e214)
Solutions
- 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.
- 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.
- 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.
- 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.
- 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
- Minimize the gap between Head and Get to reduce ETag/precondition races.
- Keep SSE-Customer key fields consistent across head and get.
- Log the OpcRequestId from the error so support can trace the call.
- Avoid concurrent writers mutating the same state object.
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
- failed to upload object: %w
- failed to access object '%s' in bucket '%s': %w
- unable to read 'content' from response: %w
- object %q is empty
- uploadSinglePartObject: data is empty
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/29779c6ff26f42c0.
Report an issue: GitHub.