hashicorp/terraform · error
failed to read existing lock file content
Error message
failed to read existing lock file content: %w
What it means
The lock-file GetObject succeeded but io.ReadAll failed while reading its (small) body. The stream was interrupted between headers and the full body read.
Solutions
- Retry the Unlock — the lock file content has not changed, only the stream broke.
- Stabilize the network path; lock files are small, so chronic failures indicate a connectivity issue.
- If retries keep failing, inspect the lock object directly in the bucket to confirm it is intact.
Example fix
// before: single Unlock attempt that dies on a network blip
return client.Unlock(id)
// after: retry on read-content failures
for i := 0; i < 3; i++ {
err := client.Unlock(id)
if err == nil { return nil }
if strings.Contains(err.Error(), "failed to read existing lock file content") {
time.Sleep(backoff(i)); continue
}
return err
}
return err Defensive patterns
Strategy: retry
Type guard
func isLockReadErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "failed to read existing lock file content")
} Try / catch
// Retry unlock on transient body-read failures
for i := 0; i < 3; i++ {
err := c.Unlock(id)
if err == nil || !isLockReadErr(err) { return err }
time.Sleep(backoff(i))
} Prevention
- Lock files are tiny — chronic read failures indicate a real network issue; fix that first.
- Stabilize the network path before retrying to avoid burning attempts.
- Log the underlying io.ReadAll error for diagnosis.
- Avoid concurrent unlocks that delete the lock mid-read.
When it happens
Trigger: Connection dropped mid-read of the lock file; server reset the stream; client context cancelled during the read.
Common situations: Flaky network during unlock; CI runner under heavy load dropping idle connections; aggressive read timeout.
Related errors
- unable to read 'content' from response
- can not read private key from
- can't read
- error reading source block
- Error unlocking oci state. Lock ID
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/3cf40f658fbd5e72.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/oci/client.go:316
// getLockInfo retrieves and parses a lock file from an oci bucket.
func (c *RemoteClient) getLockInfo(ctx context.Context) (*statemgr.LockInfo, string, error) {
// Attempt to retrieve the lock file from
getRequest := objectstorage.GetObjectRequest{
NamespaceName: common.String(c.namespace),
ObjectName: common.String(c.lockFilePath),
BucketName: common.String(c.bucketName),
RequestMetadata: common.RequestMetadata{
RetryPolicy: getDefaultRetryPolicy(),
},
}
getResponse, err := c.objectStorageClient.GetObject(ctx, getRequest)
if err != nil {
return nil, "", fmt.Errorf("failed to get existing lock file: %w", err)
}
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 {View on GitHub (pinned to d32a084675)