usememos/memos · error

S3 object payload is missing

Error message

S3 object payload is missing

What it means

ResolveAttachmentS3Driver throws "S3 object payload is missing" when attachment.Payload is present but its oneof content does not carry an S3Object (e.g. it only holds a LOCAL file descriptor). Only S3-backed attachments can be resolved to an S3 storage driver.

Source

Thrown at store/attachment.go:288

			}
			return instanceStorageSetting, nil
		}
	}
	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.

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Branch on attachment.StorageType (or payload.GetS3Object() != nil) before calling ResolveAttachmentS3Driver
  2. Use the local file path for LOCAL attachments instead of S3 resolution
  3. Verify the payload oneof is set to s3_object when writing S3 attachments

Example fix

// before
driver, obj, err := store.ResolveAttachmentS3Driver(ctx, att) // att is LOCAL
// after
if att.Payload.GetS3Object() == nil {
    return serveLocalFile(att)
}
driver, obj, err := store.ResolveAttachmentS3Driver(ctx, att)
Defensive patterns

Strategy: type-guard

Validate before calling

if attachment.Payload.GetS3Object() == nil {
    // not S3-backed; use the local path instead
}

Type guard

func isS3Attachment(a *store.Attachment) bool {
    return a != nil && a.Payload != nil && a.Payload.GetS3Object() != nil
}

Prevention

When it happens

Trigger: Calling S3 resolution on an attachment whose StorageType is LOCAL, or whose payload oneof is unset/holds a different message type.

Common situations: Instance switched from S3 to local storage but old code paths still try S3 resolution for all attachments; branching on the wrong field before choosing the resolution path.

Related errors


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