For storing user-uploaded avatars, S3-compatible object storage gives a game backend a familiar object boundary without making retention somebody else's problem. When a player's upload cannot be downloaded, the on-call page should tell you more than object missing . It should show the bucket, logical upload ID, deletion policy, and the age of the object. The earlier signal is usually quieter: a rising gap between records marked for deletion and objects actually deleted.
Short answer: use private S3-compatible object storage behind a small application interface, and treat retention and deletion as application state rather than as a vendor-specific promise. Keep the object key opaque, issue short-lived signed downloads, and make a deletion job idempotent.…