{"record":{"id":"6d810bdcd938c5d8","repo":"kopia/kopia","slug":"object-locking-unsupported","errorCode":null,"errorMessage":"object locking unsupported","messagePattern":"object locking unsupported","errorType":"exception","errorClass":"ErrUnsupportedObjectLock","httpStatus":null,"severity":"warning","filePath":"repo/blob/storage.go","lineNumber":46,"sourceCode":"\n// ErrInvalidCredentials is returned when the token used for\n// authenticating with a storage provider has expired.\nvar ErrInvalidCredentials = errors.Errorf(InvalidCredentialsErrStr)\n\n// ErrBlobAlreadyExists is returned when attempting to put a blob that already exists.\nvar ErrBlobAlreadyExists = errors.New(\"blob already exists\")\n\n// ErrUnsupportedPutBlobOption is returned when a PutBlob option that is not supported\n// by an implementation of Storage is specified in a PutBlob call.\nvar ErrUnsupportedPutBlobOption = errors.New(\"unsupported put-blob option\")\n\n// ErrNotAVolume is returned when attempting to use a Volume method against a storage\n// implementation that does not support the intended functionality.\nvar ErrNotAVolume = errors.New(\"unsupported method, storage is not a volume\")\n\n// ErrUnsupportedObjectLock is returned when attempting to use an Object Lock specific\n// function on a storage implementation that does not have the intended functionality.\nvar ErrUnsupportedObjectLock = errors.New(\"object locking unsupported\")\n\n// ApplicationID is sent to storage providers as metadata in the User-Agent of requests.\n// It is used to identify the application making the request.\nvar ApplicationID = \"kopia\"\n\n// Bytes encapsulates a sequence of bytes, possibly stored in a non-contiguous buffers,\n// which can be written sequentially or treated as a io.Reader.\ntype Bytes interface {\n\tio.WriterTo\n\n\tLength() int\n\tReader() io.ReadSeekCloser\n}\n\n// OutputBuffer is implemented by *gather.WriteBuffer.\ntype OutputBuffer interface {\n\tio.Writer\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/repo/blob/storage.go#L28-L64","documentation":"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.","triggerScenarios":"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).","commonSituations":"Users attempting to set/extend retention on repositories stored in filesystem, SFTP, or S3 buckets without object locking enabled.","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"],"exampleFix":"// before\nerr := storage.ExtendBlobRetention(ctx, blobID, opts)\n// after\nif extender, ok := storage.(interface{ ExtendBlobRetention(context.Context, blob.ID, blob.ExtendOptions) error }); ok && !isDefaultProvider(storage) {\n    err := extender.ExtendBlobRetention(ctx, blobID, opts)\n} else {\n    log.Printf(\"retention extension unsupported for this storage\")\n}","handlingStrategy":"fallback","validationCode":"_, ok := storage.(interface{ ExtendBlobRetention(context.Context, blob.ID, blob.ExtendOptions) error })\nif !ok { /* provider does not support retention extension */ }","typeGuard":"func supportsRetentionExt(s blob.Storage) bool {\n    _, ok := s.(interface{ ExtendBlobRetention(context.Context, blob.ID, blob.ExtendOptions) error })\n    return ok\n}","tryCatchPattern":"if err := st.ExtendBlobRetention(ctx, id, opts); err != nil {\n    if errors.Is(err, blob.ErrUnsupportedObjectLock) {\n        log.Warn(\"retention extension unsupported, skipping\")\n        return nil\n    }\n    return err\n}","preventionTips":["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"],"tags":["go","storage","object-lock","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}