hashicorp/terraform · error
blob metadata was empty
Error message
blob metadata %q was empty
What it means
Returned by getLockInfo when the blob's metadata map has no terraformlockid value (raw == ""). This means the blob appears to be leased (getLockInfo was called from Lock/Unlock paths) but Terraform's lock metadata is missing — typically because the lease was acquired outside Terraform, writeLockInfo was interrupted, or the metadata was deleted manually.
Solutions
- Inspect the lease and metadata via `az storage blob show --account-name <acct> -c <container> -n <blob>`.
- Break the lease manually: `az storage blob lease break --account-name <acct> -c <container> -b <blob>`.
- After the lease is broken, retry terraform — a fresh lock will be written correctly.
- Avoid leasing the state blob outside terraform.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: ensure the blob has terraformlockid metadata before trusting the lease.
func hasLockMetadata(ctx context.Context, acct, container, blob string) error {
cmd := exec.CommandContext(ctx, "az", "storage", "blob", "show",
"--account-name", acct, "-c", container, "-n", blob, "--query", "metadata.terraformlockid", "-o", "tsv")
out, err := cmd.Output()
if err != nil { return err }
if strings.TrimSpace(string(out)) == "" { return fmt.Errorf("blob metadata missing terraformlockid") }
return nil
} Try / catch
// If getLockInfo fails on empty metadata, break the lease manually rather than relying on force-unlock.
_, err := client.Unlock(id)
if err != nil && strings.Contains(err.Error(), "blob metadata") {
// break lease out-of-band
log.Printf("lock metadata missing; break the lease manually: az storage blob lease break ...")
} Prevention
- Never lease the state blob outside terraform.
- If a run crashes mid-Lock, immediately inspect metadata and break the lease if absent.
- Periodically audit the state blob's lease/metadata via `az storage blob show`.
When it happens
Trigger: (a) Someone acquired a lease via Azure portal / CLI / SDK directly on the state blob. (b) writeLockInfo partially completed — lease acquired but SetMetaData failed. (c) Metadata cleared out-of-band. (d) Blob was leased as part of an Azure backup / sync tool.
Common situations: Break-glass operation by an SRE using Azure CLI; partial lock from a terraform process killed between AcquireLease and writeLockInfo; third-party backup tooling that leases blobs.
Related errors
- failed to retrieve lock info
- Error unlocking Azure state. Lock ID
- state blob is already locked
- failed to lock azure state
- error snapshotting Blob
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/ec73d9e0118f673c.
Report an issue: GitHub.
Appendix: source
Thrown at internal/backend/remote-state/azure/client.go:228
return info.ID, nil
}
func (c *RemoteClient) getLockInfo() (*statemgr.LockInfo, error) {
options := blobs.GetPropertiesInput{}
if c.leaseID != "" {
options.LeaseID = &c.leaseID
}
ctx := newCtx()
blob, err := c.giovanniBlobClient.GetProperties(ctx, c.containerName, c.keyName, options)
if err != nil {
return nil, err
}
raw := blob.MetaData[lockInfoMetaKey]
if raw == "" {
return nil, fmt.Errorf("blob metadata %q was empty", lockInfoMetaKey)
}
data, err := base64.StdEncoding.DecodeString(raw)
if err != nil {
return nil, err
}
lockInfo := &statemgr.LockInfo{}
err = json.Unmarshal(data, lockInfo)
if err != nil {
return nil, err
}
return lockInfo, nil
}
// writes info to blob meta data, deletes metadata entry if info is nil
func (c *RemoteClient) writeLockInfo(info *statemgr.LockInfo) error {View on GitHub (pinned to d32a084675)