hashicorp/terraform · error

Failed to retrieve lock information from OCI Object Storage:

Error message

Failed to retrieve lock information from OCI Object Storage: %w

What it means

Raised in Unlock as the outer wrap over any failure returned by getLockInfo (errors 307/308/309). Unlock must read and parse the existing lock file before it can verify the ID and issue the conditional DeleteObject, so any failure to retrieve or parse lock information surfaces through this message.

Source

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

	}
	lockByteData, err := io.ReadAll(getResponse.Content)
	if err != nil {
		return nil, *getResponse.ETag, fmt.Errorf("failed to read existing lock file content: %w", err)
	}
	lockInfo := &statemgr.LockInfo{}
	if err := json.Unmarshal(lockByteData, lockInfo); err != nil {
		return lockInfo, "", fmt.Errorf("failed to unmarshal JSON data into LockInfo struct: %w", err)
	}
	return lockInfo, *getResponse.ETag, nil
}
func (c *RemoteClient) Unlock(id string) error {
	ctx := context.TODO()
	logger := logWithOperation("unlock-state-file").Named(c.lockFilePath)
	logger.Info("unlocking remote state")
	lockInfo, etag, err := c.getLockInfo(ctx)

	if err != nil {
		return fmt.Errorf("Failed to retrieve lock information from OCI Object Storage: %w", err)
	}
	// Verify that the provided lock ID matches the lock ID of the retrieved lock file.
	if lockInfo.ID != id {
		return &statemgr.LockError{
			Info: lockInfo,
			Err:  fmt.Errorf("lock ID '%s' does not match the existing lock ID '%s'", id, lockInfo.ID),
		}
	}

	deleteRequest := objectstorage.DeleteObjectRequest{
		NamespaceName: common.String(c.namespace),
		ObjectName:    common.String(c.lockFilePath),
		BucketName:    common.String(c.bucketName),
		IfMatch:       common.String(etag),
		RequestMetadata: common.RequestMetadata{
			RetryPolicy: getDefaultRetryPolicy(),
		},
	}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Unwrap the error to see whether it is 307 (get), 308 (read), or 309 (unmarshal) and follow that sub-error's fix.
  2. For a missing lock file (404 under the wrap), the lock is already gone — verify with 'oci os object list --prefix <lockfile>' and clear any stale local state.
  3. For a corrupt lock file, follow the unmarshal fix: inspect/delete the lock object once you confirm no real holder exists.
  4. Re-run the unlock after fixing the underlying read/parse issue.
Defensive patterns

Strategy: retry

Validate before calling

// Probe lock file presence before attempting a full Unlock:
//   oci os object head --namespace <ns> --bucket-name <b> --name <lockfile>
// If absent, skip Unlock (nothing to release).

Type guard

// Unwrap to find the specific sub-cause (307/308/309):
var se common.ServiceError
if errors.As(err, &se) && se.GetHTTPStatusCode() == 404 { /* no lock -> already unlocked */ }

Try / catch

lockInfo, etag, err := c.getLockInfo(ctx)
if err != nil {
    return fmt.Errorf("Failed to retrieve lock information from OCI Object Storage: %w", err)
}

Prevention

When it happens

Trigger: Unlock calls getLockInfo (client.go:328) which returns a non-nil error: GetObject fails (307), body read fails (308), or JSON unmarshal fails (309). The wrapped %w carries the specific sub-cause.

Common situations: Running 'terraform force-unlock'/'terraform unlock' when the lock file is missing, unreadable, or corrupt; IAM lacking read on the bucket at unlock time; transient read/parse failure.

Related errors


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