kopia/kopia · warning · ErrUnsupportedObjectLock
object locking unsupported
Error message
object locking unsupported
What it means
ErrUnsupportedObjectLock is a sentinel error returned by blob storage providers that do not implement Object Lock functionality. ExtendBlobRetention in DefaultProviderImplementation always returns it, signaling that the backing storage cannot extend blob retention.
Solutions
- Do not call ExtendBlobRetention unless the storage provider supports Object Lock; check provider capabilities first
- Use an S3-backed provider with Object Lock enabled on the bucket
- Handle the error gracefully and treat retention extension as a no-op for this provider
Example fix
// before
err := storage.ExtendBlobRetention(ctx, blobID, opts)
// after
if extender, ok := storage.(interface{ ExtendBlobRetention(context.Context, blob.ID, blob.ExtendOptions) error }); ok && !isDefaultProvider(storage) {
err := extender.ExtendBlobRetention(ctx, blobID, opts)
} else {
log.Printf("retention extension unsupported for this storage")
} Defensive patterns
Strategy: fallback
Validate before calling
_, ok := storage.(interface{ ExtendBlobRetention(context.Context, blob.ID, blob.ExtendOptions) error })
if !ok { /* provider does not support retention extension */ } Type guard
func supportsRetentionExt(s blob.Storage) bool {
_, ok := s.(interface{ ExtendBlobRetention(context.Context, blob.ID, blob.ExtendOptions) error })
return ok
} Try / catch
if err := st.ExtendBlobRetention(ctx, id, opts); err != nil {
if errors.Is(err, blob.ErrUnsupportedObjectLock) {
log.Warn("retention extension unsupported, skipping")
return nil
}
return err
} Prevention
- Check provider capabilities before calling retention APIs
- Only enable retention features with S3 Object Lock-enabled storage
- Treat ErrUnsupportedObjectLock as a feature-availability signal, not a failure
When it happens
Trigger: Calling ExtendBlobRetention on a storage provider whose implementation does not support Object Lock (e.g. the default provider, or non-S3 providers without object-lock capability).
Common situations: Users attempting to set/extend retention on repositories stored in filesystem, SFTP, or S3 buckets without object locking enabled.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- blob configuration
- BLOB not found
- content not found
- error auto-compacting contents
- error cleaning up index blobs
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/6d810bdcd938c5d8.
Report an issue: GitHub.
Appendix: source
Thrown at repo/blob/storage.go:46
// ErrInvalidCredentials is returned when the token used for
// authenticating with a storage provider has expired.
var ErrInvalidCredentials = errors.Errorf(InvalidCredentialsErrStr)
// ErrBlobAlreadyExists is returned when attempting to put a blob that already exists.
var ErrBlobAlreadyExists = errors.New("blob already exists")
// ErrUnsupportedPutBlobOption is returned when a PutBlob option that is not supported
// by an implementation of Storage is specified in a PutBlob call.
var ErrUnsupportedPutBlobOption = errors.New("unsupported put-blob option")
// ErrNotAVolume is returned when attempting to use a Volume method against a storage
// implementation that does not support the intended functionality.
var ErrNotAVolume = errors.New("unsupported method, storage is not a volume")
// ErrUnsupportedObjectLock is returned when attempting to use an Object Lock specific
// function on a storage implementation that does not have the intended functionality.
var ErrUnsupportedObjectLock = errors.New("object locking unsupported")
// ApplicationID is sent to storage providers as metadata in the User-Agent of requests.
// It is used to identify the application making the request.
var ApplicationID = "kopia"
// Bytes encapsulates a sequence of bytes, possibly stored in a non-contiguous buffers,
// which can be written sequentially or treated as a io.Reader.
type Bytes interface {
io.WriterTo
Length() int
Reader() io.ReadSeekCloser
}
// OutputBuffer is implemented by *gather.WriteBuffer.
type OutputBuffer interface {
io.Writer
View on GitHub (pinned to 82495e54b5)