kopia/kopia · error
unable to extend retention period
Error message
unable to extend retention period
What it means
Kopia wraps the Azure Blob SetImmutabilityPolicy call when extending a blob's time-based retention (WORM immutability) so an existing retention window can be lengthened. The underlying Azure SDK rejected or failed the SetImmutabilityPolicy request, so the blob's retention period was not extended. This is a hard failure because shortening or missing immutability windows can break compliance guarantees.
Solutions
- Verify the storage account has version-level immutability enabled and the blob already has an immutability policy
- Ensure the new retainUntilDate is strictly later than the current policy's expiry
- Check the credentials/RBAC role can write immutability policies (Storage Blob Data Owner)
- If the policy is locked, only extensions are allowed — confirm Mode is set appropriately and dates comply
- Retry on transient network/5xx errors
Example fix
// before
err := az.extendImmutability(ctx, b, newDate) // fails if newDate <= current expiry
// after
if !newDate.After(currentPolicy.ExpiresOn) {
return errors.Errorf("new retain-until %v must be after current expiry %v", newDate, currentPolicy.ExpiresOn)
}
err := az.extendImmutability(ctx, b, newDate) Defensive patterns
Strategy: try-catch
Validate before calling
// verify blob has an immutability policy and new date is later
prop, _ := blobClient.GetProperties(ctx, nil)
if prop.ImmutabilityPolicyExpiresOn == nil {
return fmt.Errorf("blob %s has no immutability policy to extend", blobName)
}
if !newRetainUntil.After(*prop.ImmutabilityPolicyExpiresOn) {
return fmt.Errorf("new retain-until %v must be after current %v", newRetainUntil, *prop.ImmutabilityPolicyExpiresOn)
} Try / catch
err := az.ExtendBlobRetention(ctx, blobID, retainUntil)
var azErr azcore.ResponseError
if errors.As(err, &azErr) {
switch azErr.StatusCode {
case 409: // conflict: locked policy or non-increasing date
// inspect azErr.ErrorCode and adjust retention date
case 403: // permission denied on immutability policy write
}
}
return err Prevention
- Enable version-level immutability on the storage account before using retention features
- Always extend retention with dates strictly later than the current expiry
- Grant Storage Blob Data Owner for immutability policy operations
- Log the wrapped Azure ResponseError code for diagnosis
When it happens
Trigger: Calling ExtendBlobRetention on a blob that has no immutability policy yet, on a blob locked (Mounted) in immutability mode where policy changes are restricted, with a retainUntilDate earlier than or equal to the current policy date, or when the request fails due to auth/permissions/network issues.
Common situations: Storage account without version-level immutability support enabled; attempting to extend retention on an already-locked policy with conflicting settings; RBAC role lacking the immutability policy write permission; transient Azure API errors during retention sweeps.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- failed to create delete marker for immutable blob
- failed to put blob version needed to create delete marker
- failed to soft delete blob
- Attributes
- container name must be specified
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/cae88c2576343d13.
Report an issue: GitHub.
Appendix: source
Thrown at repo/blob/azure/azure_storage.go:187
return az.retryDeleteBlob(ctx, b)
}
return err
}
// ExtendBlobRetention extends a blob retention period.
func (az *azStorage) ExtendBlobRetention(ctx context.Context, b blob.ID, opts blob.ExtendOptions) error {
retainUntilDate := clock.Now().Add(opts.RetentionPeriod).UTC()
mode := azblobblob.ImmutabilityPolicySetting(blob.Locked) // overwrite the S3 values
_, err := az.service.ServiceClient().
NewContainerClient(az.Container).
NewBlobClient(az.getObjectNameString(b)).
SetImmutabilityPolicy(ctx, retainUntilDate, &azblobblob.SetImmutabilityPolicyOptions{
Mode: &mode,
})
if err != nil {
return errors.Wrap(err, "unable to extend retention period")
}
return nil
}
func (az *azStorage) getObjectNameString(b blob.ID) string {
return az.Prefix + string(b)
}
// ListBlobs list azure blobs with given prefix.
func (az *azStorage) ListBlobs(ctx context.Context, prefix blob.ID, callback func(blob.Metadata) error) error {
prefixStr := az.getObjectNameString(prefix)
pager := az.service.NewListBlobsFlatPager(az.container, &azblob.ListBlobsFlatOptions{
Prefix: &prefixStr,
Include: azblob.ListBlobsInclude{
Metadata: true,
},View on GitHub (pinned to 82495e54b5)