kopia/kopia · warning · ErrUnsupportedPutBlobOption

unsupported put-blob option

Error message

unsupported put-blob option

What it means

ErrUnsupportedPutBlobOption is a sentinel in repo/blob/storage.go returned when a PutBlob call carries an option the Storage implementation does not support, such as retention (Object Lock) settings or DoNotRecreate. It lets backends advertise capability limits instead of silently ignoring options.

Solutions

  1. Detect and drop the unsupported option: on errors.Is(err, blob.ErrUnsupportedPutBlobOption), retry PutBlob without retention/DoNotRecreate.
  2. Use a backend supporting the feature (e.g. S3 with Object Lock enabled) if retention is mandatory.
  3. For DoNotRecreate, implement existence checks manually (GetMetadata first) instead of relying on the option.
  4. Note providervalidation treats this sentinel as acceptable — your workflow may safely ignore it too.

Example fix

// before
if err := st.PutBlob(ctx, id, data, opts); err != nil { return err }
// after
if err := st.PutBlob(ctx, id, data, opts); err != nil {
    if errors.Is(err, blob.ErrUnsupportedPutBlobOption) {
        opts.RetentionPeriod = 0
        opts.EncryptionKeyID = ""
        return st.PutBlob(ctx, id, data, opts)
    }
    return err
}
Defensive patterns

Strategy: fallback

Try / catch

if err := st.PutBlob(ctx, id, data, opts); err != nil {
    if errors.Is(err, blob.ErrUnsupportedPutBlobOption) {
        opts.RetentionPeriod = 0 // retry without unsupported options
        return st.PutBlob(ctx, id, data, opts)
    }
    return err
}

Prevention

When it happens

Trigger: PutBlob with PutOptions.HasRetentionOptions() on a backend without object-lock support, or with DoNotRecreate=true on a backend that cannot honor it; internal/blobtesting/map.go wraps it with 'blob-retention'/'do-not-recreate' context.

Common situations: Syncing to or writing on S3-compatible stores lacking Object Lock; providers that always allow recreate; tests/providervalidation that detect and accept this sentinel as 'feature not supported here'.

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


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/498542f51f5eea27. Report an issue: GitHub.

Appendix: source

Thrown at repo/blob/storage.go:38

var ErrSetTimeUnsupported = errors.New("SetTime is not supported")

// ErrInvalidRange is returned when the requested blob offset or length is invalid.
var ErrInvalidRange = errors.New("invalid blob offset or length")

// InvalidCredentialsErrStr is the error string returned by the provider
// when a token has expired.
const InvalidCredentialsErrStr = "The provided token has expired"

// 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

View on GitHub (pinned to 82495e54b5)