Skip to content

Non existent images sizes have null fields with original URL in the database (storage-s3) #15450

@jhb-dev

Description

@jhb-dev

Describe the Bug

When using the S3 storage adapter (@payloadcms/storage-s3) with an upload collection that defines multiple image sizes (e.g., xs, sm, md, lg, xl), and withoutEnlargement is set to undefined (the default), uploading an image that is smaller than some of the defined size breakpoints results in inconsistent data in the database.

For sizes that cannot be generated (because the original image is smaller than the target size), Payload:

  1. Creates database entries for these sizes with null values for width, height, mimeType, filesize, and filename
  2. sets the url field for these sizes to the original image URL (e.g., /api/images/file/filename.jpeg)

This is problematic because:

  • The database contains entries for sizes that don't actually exist
  • The URL field for these sizes points to the original (full-sized) image URL
  • Applications consuming this data may incorrectly assume these sizes exist

Example

When uploading an image that is 1200px wide with sizes defined for xs (320), sm (640), md (1024), lg (1600), and xl (2048):

Expected behavior: Sizes lg and xl should either:

  • Not be created in the database at all, OR
  • Have a clear indicator that they don't exist (e.g., null for the entire size object)

Actual behavior:

{
  "url": "/api/images/file/6962ed2b04509.jpg",
  // other fields...
  "sizes": {
    "md": {
      "url": "/api/images/file/6962ed2b04509-1024x1333.jpg",
      "width": 1024,
      "height": 1333,
      "mimeType": "image/jpeg",
      "filesize": 168541,
      "filename": "6962ed2b04509-1024x1333.jpg"
    },
    "lg": {
      "url": "/api/images/file/6962ed2b04509.jpg",
      "width": null,
      "height": null,
      "mimeType": null,
      "filesize": null,
      "filename": null
    },
    "xl": {
      "url": "/api/images/file/6962ed2b04509.jpg",
      "width": null,
      "height": null,
      "mimeType": null,
      "filesize": null,
      "filename": null
    }
  }
}

Link to the code that reproduces this issue

https://github.com/jhb-dev/payload-s3-image-sizes-null

Reproduction Steps

  1. Clone the reproduction repository and run the development server
  2. Configure your S3 credentials in the .env file
  3. Start the dev server with pnpm dev
  4. Upload an image that is smaller than the largest defined sizes (e.g., upload an image that is 1200px wide - this is smaller than the lg (1600px) and xl (2048px) sizes)
  5. After upload, inspect the document in the database (or via the API at /api/images)
  6. Observe that lg and xl sizes have null values for all fields except url

Which area(s) are affected?

plugin: storage-*

Environment Info

Binaries:
  Node: 24.3.0
  npm: 11.4.2
  Yarn: 1.22.22
  pnpm: 10.28.1
Relevant Packages:
  payload: 3.74.0
  next: 15.4.11
  @payloadcms/db-mongodb: 3.74.0
  @payloadcms/graphql: 3.74.0
  @payloadcms/next/utilities: 3.74.0
  @payloadcms/plugin-cloud-storage: 3.74.0
  @payloadcms/richtext-lexical: 3.74.0
  @payloadcms/storage-s3: 3.74.0
  @payloadcms/translations: 3.74.0
  @payloadcms/ui/shared: 3.74.0
  react: 19.2.1
  react-dom: 19.2.1
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions