{"record":{"id":"dfedd2d54d0871db","repo":"hashicorp/terraform","slug":"failed-to-retrieve-lock-info-for-lock-id-q-s","errorCode":null,"errorMessage":"failed to retrieve lock info for lock ID %q: %s","messagePattern":"failed to retrieve lock info for lock ID %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/s3/client.go","lineNumber":567,"sourceCode":"\t\tKey:    aws.String(c.lockFilePath),\n\t})\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete the lock file: %w\", err)\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Deleted lock file: '%q'\", c.lockFilePath))\n\n\treturn nil\n}\n\nfunc (c *RemoteClient) unlockWithDynamoDB(ctx context.Context, id string, lockErr *statemgr.LockError) error {\n\t// TODO: store the path and lock ID in separate fields, and have proper\n\t// projection expression only delete the lock if both match, rather than\n\t// checking the ID from the info field first.\n\tlockInfo, err := c.getLockInfoWithDynamoDB(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to retrieve lock info for lock ID %q: %s\", id, err)\n\t}\n\tlockErr.Info = lockInfo\n\n\tif lockInfo.ID != id {\n\t\treturn fmt.Errorf(\"lock ID %q does not match existing lock (%q)\", id, lockInfo.ID)\n\t}\n\n\tparams := &dynamodb.DeleteItemInput{\n\t\tKey: map[string]dynamodbtypes.AttributeValue{\n\t\t\t\"LockID\": &dynamodbtypes.AttributeValueMemberS{\n\t\t\t\tValue: c.lockPath(),\n\t\t\t},\n\t\t},\n\t\tTableName: aws.String(c.ddbTable),\n\t}\n\t_, err = c.dynClient.DeleteItem(ctx, params)\n\n\tif err != nil {","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/backend/remote-state/s3/client.go#L549-L585","documentation":"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.","triggerScenarios":"Unlock -> unlockWithDynamoDB -> getLockInfoWithDynamoDB returns an error: DynamoDB GetItem fails (table missing, AccessDenied, throttling) or the Info attribute contains malformed JSON.","commonSituations":"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.","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."],"exampleFix":"# before: malformed Info attribute\n# after: write valid LockInfo JSON\naws dynamodb put-item --table-name locks \\\n  --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>\\\"}\"}}'","handlingStrategy":"validation","validationCode":"// Pre-flight: table reachable and Info attribute is valid JSON\nfunc validateDynamoLock(ctx context.Context, ddbs *dynamodb.Client, table, lockID string) error {\n  if _, err := ddbs.DescribeTable(ctx, &dynamodb.DescribeTableInput{TableName: &table}); err != nil {\n    return fmt.Errorf(\"table %q: %w\", table, err)\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":"if err := client.Unlock(id); err != nil {\n    if strings.Contains(err.Error(), \"failed to retrieve lock info\") {\n        // DDB read failed; check table existence and IAM before retry\n    }\n}","preventionTips":["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."],"tags":["dynamodb","terraform-state","locking","iam","aws"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}