hashicorp/terraform · error
failed to retrieve lock info for lock ID %q: %s
Error message
failed to retrieve lock info for lock ID %q: %s
What it means
Returned by unlockWithDynamoDB when getLockInfoWithDynamoDB fails (GetItem error or JSON unmarshal failure of the Info attribute). The message includes the attempted lock id and the wrapped retrieval error. This blocks the DynamoDB-side unlock because the code must first read the stored lock to verify ownership.
Source
Thrown at internal/backend/remote-state/s3/client.go:567
Key: aws.String(c.lockFilePath),
})
if err != nil {
return fmt.Errorf("failed to delete the lock file: %w", err)
}
log.Debug(fmt.Sprintf("Deleted lock file: '%q'", c.lockFilePath))
return nil
}
func (c *RemoteClient) unlockWithDynamoDB(ctx context.Context, id string, lockErr *statemgr.LockError) error {
// TODO: store the path and lock ID in separate fields, and have proper
// projection expression only delete the lock if both match, rather than
// checking the ID from the info field first.
lockInfo, err := c.getLockInfoWithDynamoDB(ctx)
if err != nil {
return fmt.Errorf("failed to retrieve lock info for lock ID %q: %s", id, err)
}
lockErr.Info = lockInfo
if lockInfo.ID != id {
return fmt.Errorf("lock ID %q does not match existing lock (%q)", id, lockInfo.ID)
}
params := &dynamodb.DeleteItemInput{
Key: map[string]dynamodbtypes.AttributeValue{
"LockID": &dynamodbtypes.AttributeValueMemberS{
Value: c.lockPath(),
},
},
TableName: aws.String(c.ddbTable),
}
_, err = c.dynClient.DeleteItem(ctx, params)
if err != nil {View on GitHub (pinned to c9def3e214)
Solutions
- Confirm dynamodb:GetItem permission and that the table name in the backend config matches the live table.
- If the table is gone, recreate it (or remove dynamodb_table from the config if migrating to S3-native locking).
- Inspect the row's Info attribute: aws dynamodb get-item --table-name <tbl> --key '{...}' --projection-expression Info.
- Repair or overwrite the Info JSON if it is malformed.
Example fix
# before: malformed Info attribute
# after: write valid LockInfo JSON
aws dynamodb put-item --table-name locks \
--item '{"LockID":{"S":"<bucket>/<path>"},"Info":{"S":"{\"ID\":\"x\",\"Operation\":\"OperationTypeInvalid\",\"Who\":\"ci\",\"Version\":\"1.0\",\"Created\":\"2024-01-01T00:00:00Z\",\"Path\":\"<bucket>/<path>\"}"}}' Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: table reachable and Info attribute is valid JSON
func validateDynamoLock(ctx context.Context, ddbs *dynamodb.Client, table, lockID string) error {
if _, err := ddbs.DescribeTable(ctx, &dynamodb.DescribeTableInput{TableName: &table}); err != nil {
return fmt.Errorf("table %q: %w", table, err)
}
return nil
} Try / catch
if err := client.Unlock(id); err != nil {
if strings.Contains(err.Error(), "failed to retrieve lock info") {
// DDB read failed; check table existence and IAM before retry
}
} Prevention
- Run a DescribeTable pre-flight on the lock table.
- Grant dynamodb:GetItem on the lock table ARN.
- Keep the Info attribute untouched by external tooling.
- Pin Terraform version so LockInfo JSON schema is consistent.
When it happens
Trigger: Unlock -> unlockWithDynamoDB -> getLockInfoWithDynamoDB returns an error: DynamoDB GetItem fails (table missing, AccessDenied, throttling) or the Info attribute contains malformed JSON.
Common situations: Lock table dropped or renamed; IAM lacks dynamodb:GetItem; Info attribute corrupted by an older/incompatible Terraform or by a manual edit; throttling on a small provisioned table.
Related errors
- failed to unlock both S3 and DynamoDB: S3 error: %v, DynamoD
- failed to unlock DynamoDB: %v
- failed to unlock S3: %v
- unable to retrieve file from S3 bucket '%s' with key '%s': %
- failed to delete the lock file: %w
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/dfedd2d54d0871db.
Report an issue: GitHub.