{"record":{"id":"750c91c43dec6138","repo":"hashicorp/terraform","slug":"error-snapshotting-blob-q-container-q-account","errorCode":null,"errorMessage":"error snapshotting Blob %q (Container %q / Account %q): %+v","messagePattern":"error snapshotting Blob %q \\(Container %q / Account %q\\): %\\+v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/backend/remote-state/azure/client.go","lineNumber":102,"sourceCode":"\tsetOptions := blobs.SetPropertiesInput{}\n\tputOptions := blobs.PutBlockBlobInput{}\n\n\toptions := blobs.GetInput{}\n\tif c.leaseID != \"\" {\n\t\toptions.LeaseID = &c.leaseID\n\t\tgetOptions.LeaseID = &c.leaseID\n\t\tsetOptions.LeaseID = &c.leaseID\n\t\tputOptions.LeaseID = &c.leaseID\n\t}\n\n\tctx := newCtx()\n\n\tif c.snapshot {\n\t\tsnapshotInput := blobs.SnapshotInput{LeaseID: options.LeaseID}\n\n\t\tlog.Printf(\"[DEBUG] Snapshotting existing Blob %q (Container %q / Account %q)\", c.keyName, c.containerName, c.accountName)\n\t\tif _, err := c.giovanniBlobClient.Snapshot(ctx, c.containerName, c.keyName, snapshotInput); err != nil {\n\t\t\treturn diags.Append(fmt.Errorf(\"error snapshotting Blob %q (Container %q / Account %q): %+v\", c.keyName, c.containerName, c.accountName, err))\n\t\t}\n\n\t\tlog.Print(\"[DEBUG] Created blob snapshot\")\n\t}\n\n\tblob, err := c.giovanniBlobClient.GetProperties(ctx, c.containerName, c.keyName, getOptions)\n\tif err != nil {\n\t\tif !response.WasNotFound(blob.HttpResponse) {\n\t\t\treturn diags.Append(err)\n\t\t}\n\t}\n\n\tcontentType := \"application/json\"\n\tputOptions.Content = &data\n\tputOptions.ContentType = &contentType\n\tputOptions.MetaData = blob.MetaData\n\t_, err = c.giovanniBlobClient.PutBlockBlob(ctx, c.containerName, c.keyName, putOptions)\n","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/backend/remote-state/azure/client.go#L84-L120","documentation":"Thrown by RemoteClient.Put when snapshot = true and c.giovanniBlobClient.Snapshot fails before overwriting the state blob. Snapshot creates a point-in-time copy of the existing blob; failure aborts the write to protect the prior state. Causes are RBAC (cannot snapshot), lease conflict, account in read-only/locked state, or snapshot restrictions on the SKU.","triggerScenarios":"(a) Identity lacks permission to create blob snapshots (Storage Blob Data Contributor needed). (b) Blob is currently leased by another client. (c) Account is read-only or has a deny-assignment. (d) Soft-deleted / under recovery. (e) Premium SKU snapshot restrictions.","commonSituations":"Using AAD auth without Storage Blob Data Contributor; concurrent apply holds the lease; storage account has a CanNotDelete lock; account under immutable-blob / WORM policy.","solutions":["Ensure the identity has Storage Blob Data Contributor (or equivalent) on the account/container.","Set snapshot = false in the backend if snapshots are not required.","Release any conflicting leases before retrying.","Remove an Azure resource lock on the storage account if it blocks snapshots.","Check the storage account's soft-delete / WORM policy for snapshot conflicts."],"exampleFix":"// before\nterraform {\n  backend \"azurerm\" {\n    snapshot = true\n  }\n}\n// after\nterraform {\n  backend \"azurerm\" {\n    snapshot = false\n  }\n}","handlingStrategy":"validation","validationCode":"// Pre-flight: confirm the identity can snapshot blobs before enabling snapshot = true.\nfunc canSnapshotBlob(ctx context.Context, acct, container, blob string) error {\n    // attempt a snapshot on a throwaway test blob, or check role assignments\n    cmd := exec.CommandContext(ctx, \"az\", \"role\", \"assignment\", \"list\", \"--assignee\", os.Getenv(\"ARM_CLIENT_ID\"), \"--role\", \"Storage Blob Data Contributor\")\n    if out, err := cmd.Output(); err != nil || len(out) == 0 {\n        return fmt.Errorf(\"identity lacks Storage Blob Data Contributor; cannot snapshot\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// If snapshotting is non-critical, retry Put without it.\nif diags.HasErrors() && snapshotEnabled {\n    log.Printf(\"snapshot failed; retrying Put without snapshot\")\n    client.Snapshot = false\n    diags = client.Put(data)\n}","preventionTips":["Grant Storage Blob Data Contributor when using snapshot = true.","Set snapshot = false for read-only or low-churn state where history isn't needed.","Remove Azure resource locks (CanNotDelete) on storage accounts that must snapshot."],"tags":["azure","blob","snapshot","rbac","state-locking"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}