plugin-seo: GenerateImage is incorrectly typed to return a string and its field doesn't handle object values
Closed this issue · 3 comments
Describe the Bug
The return type for GenerateImage is defined as a string. The docs say that a relation field value can be returned (or at least that's what I'm reading it as). This usually passes typechecks, because the fallback type for the doc property of the first argument is any.
However: Assuming Media as the relation type, relation fields are typed by payload as number | Media. Example with the website template's Page:

I'm assuming this works for everybody because in this context, the relation is never actually resolved and the ID is returned as a number. Returning an object actually breaks the UI because the component doesn't validate the result.
- Conforming to the function signature causes a validation error when saving but does save the image
- Returning a number breaks the function signature but works flawlessly
- Returning the value of a relation field only breaks the function signature if the type is specifically asserted but works flawlessly
- Returning an object/a resolved collection value works with fresh state but breaks rendering afterwards, presumably because of #10800
Link to the code that reproduces this issue
https://github.com/apttx/payload-seo-image
Reproduction Steps
- Initialize a project using create-payload-app with the website template
- Configure auto-generation for the Meta Image field that returns a string ID
- Auto-generate a meta image and save
or in my repro
- Install & start
- Create a
Media - Create a page, auto-generate its Meta Image and save
I created my repro before creating the issue, so it doesn't strictly follow the repro guide. It does use the website template with minimal configuration changes, though. I hope that's fine, I'll otherwise create an additional minimal repro using the guide.
Which area(s) are affected? (Select all that apply)
plugin: seo
Environment Info
Binaries:
Node: 24.4.1
npm: 11.4.2
Yarn: 1.22.19
pnpm: 10.6.3
Relevant Packages:
payload: 3.56.0
next: 15.4.4
@payloadcms/email-nodemailer: 3.56.0
@payloadcms/graphql: 3.56.0
@payloadcms/live-preview: 3.56.0
@payloadcms/live-preview-react: 3.56.0
@payloadcms/next/utilities: 3.56.0
@payloadcms/payload-cloud: 3.56.0
@payloadcms/plugin-form-builder: 3.56.0
@payloadcms/plugin-nested-docs: 3.56.0
@payloadcms/plugin-redirects: 3.56.0
@payloadcms/plugin-search: 3.56.0
@payloadcms/plugin-seo: 3.56.0
@payloadcms/richtext-lexical: 3.56.0
@payloadcms/translations: 3.56.0
@payloadcms/ui/shared: 3.56.0
react: 19.1.0
react-dom: 19.1.0
Operating System:
Platform: linux
Arch: x64
Version: #1 SMP PREEMPT_DYNAMIC Mon, 01 Sep 2025 23:07:10 +0000
Available memory (MB): 31995
Available CPU cores: 16
i just realized that the string/number thing might be specific to my setup with a sql-like database. other db systems might use string ids.
🚀 This is included in version v3.57.0
This issue has been automatically locked.
Please open a new issue if this issue persists with any additional detail.