hashicorp/terraform · error

blob metadata %q was empty

Error message

blob metadata %q was empty

What it means

Raised in RemoteClient.getLockInfo (client.go:226-229). To report who holds a lock, the backend reads the blob metadata key 'terraformlockid'; if that metadata value is empty (present-but-blank or absent) while the code expects lock info, it returns this error. It usually indicates a corrupt or partially-written lock: the lease exists but the lock metadata was never written or was cleared.

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 c9def3e214)

Solutions

  1. Break the lease directly since the lock info is unrecoverable: az storage blob lease break --account-name <account> -c <container> -b <key>
  2. Then re-run 'terraform init' and the original command
  3. Avoid external tools that manipulate the state blob metadata or leases

Example fix

# the lock info metadata is empty, so force-unlock by ID won't work;
# break the lease at the Azure layer instead
az storage blob lease break \
  --account-name mystage --auth-mode login \
  -c tfstate -b "prod.terraform.tfstate"

# verify it is unlocked, then retry
terraform init
terraform apply
Defensive patterns

Strategy: validation

Validate before calling

# Detect a corrupt lock (lease present but empty metadata) before retrying
META=$(az storage blob metadata show --account-name "$ARM_STORAGE_ACCOUNT_NAME" -c "$ARM_CONTAINER_NAME" -n "$ARM_KEY" --query 'terraformlockid' -o tsv 2>/dev/null)
LEASE=$(az storage blob show --account-name "$ARM_STORAGE_ACCOUNT_NAME" -c "$ARM_CONTAINER_NAME" -n "$ARM_KEY" --query 'properties.lease.status' -o tsv 2>/dev/null)
[ "$LEASE" = "locked" ] && [ -z "$META" ] && echo "FAIL: corrupt lock (empty metadata) -> break lease (155)" || echo "OK"

Prevention

When it happens

Trigger: Produced at client.go:226-228 when blob.MetaData[lockInfoMetaKey] ("terraformlockid") is the empty string. Hit when Lock/Unlock call getLockInfo to build a LockError or to validate the holder.

Common situations: A crashed Terraform process that acquired the lease but died before writeLockInfo completed; manual lease acquisition outside Terraform; an external tool that cleared the metadata; a partial write interrupted by network failure.

Related errors


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