usememos/memos · error

S3 object key is missing

Error message

S3 object key is missing

What it means

ResolveAttachmentS3Driver throws "S3 object key is missing" when the S3Object payload exists but its Key field is an empty string. Without a key there is no object address in the bucket, so presigning or reading would be meaningless; the function fails fast rather than issuing requests for "".

Source

Thrown at store/attachment.go:291

	}
	return nil, nil
}

// ResolveAttachmentS3Driver resolves the storage driver referenced by an S3
// attachment payload, validating the payload and supplying the instance setting.
func (s *Store) ResolveAttachmentS3Driver(ctx context.Context, attachment *Attachment) (storage.Driver, *storepb.AttachmentPayload_S3Object, error) {
	if attachment == nil {
		return nil, nil, errors.New("attachment is missing")
	}
	if attachment.Payload == nil {
		return nil, nil, errors.New("attachment payload is missing")
	}
	s3Object := attachment.Payload.GetS3Object()
	if s3Object == nil {
		return nil, nil, errors.New("S3 object payload is missing")
	}
	if s3Object.Key == "" {
		return nil, nil, errors.New("S3 object key is missing")
	}

	instanceStorageSetting, err := s.GetInstanceStorageSetting(ctx)
	if err != nil {
		return nil, nil, errors.Wrap(err, "failed to get instance storage setting")
	}
	driver, err := ResolveStorageDriver(ctx, instanceStorageSetting, s3Object.StorageId, s3Object.S3Config)
	if err != nil {
		return nil, nil, errors.Wrap(err, "failed to resolve storage driver")
	}
	return driver, s3Object, nil
}

// AttachmentNeedsInstanceStorageSetting reports whether cleanup should load
// the configured storage registry for an S3 attachment.
func AttachmentNeedsInstanceStorageSetting(attachment *Attachment) bool {
	if attachment == nil || attachment.StorageType != storepb.AttachmentStorageType_S3 {
		return false

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Repair the stored payload so s3_object.key holds the real object key
  2. Validate the key is non-empty at attachment-create time before persisting
  3. If the blob is unrecoverable, delete the attachment record or mark it LOCAL-stubbed

Example fix

// before (writing)
payload.S3Object = &storepb.AttachmentPayload_S3Object{BucketId: b, StorageId: s}
// after
payload.S3Object = &storepb.AttachmentPayload_S3Object{Key: objectKey, BucketId: b, StorageId: s}
Defensive patterns

Strategy: validation

Validate before calling

if s3 := attachment.Payload.GetS3Object(); s3 == nil || s3.Key == "" {
    return errors.New("attachment has no S3 object key")
}

Type guard

func validS3Key(s3 *storepb.AttachmentPayload_S3Object) bool {
    return s3 != nil && s3.Key != ""
}

Prevention

When it happens

Trigger: Attachment rows whose payload.s3_object was stored with an empty key — usually via custom writes, migrations, or truncated serialization.

Common situations: Hand-crafted backfill scripts that set bucket but not key; payload protojson that dropped the key due to a field-name typo (e.g. "objectKey" vs "key"); deleted S3 objects leaving empty-key placeholders.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/2f33641825df77f3. Report an issue: GitHub.