payload
payload copied to clipboard
Uploaded SVGs with <?xml /> tag fail to load on page
Link to reproduction
No response
Payload Version
3.0.0-beta.73
Node Version
22.6.0
Next.js Version
15.0.0-rc.0
Describe the Bug
Recently upgraded my project to 3.0 beta. Noticed that SVG images being served by Payload are not loading correctly on my page.
If I hit the URL directly in the address bar, it works fine. Seems to be an issue only when using image tags?
Payload returns 200, Safari will actually let you inspect the DOM of the returned SVG, but it won't show an image preview.
Chrome says that no data was returned but the Content-Length response greater reflects the size of the expected SVG.
I noticed a comment on Discord that mentions similar SVG problems. This person found that removing <?xml version="1.0" encoding="utf-8"?> from the SVGs fixed the issue. My results are consistent -- removing that line results in the SVG loading without issue.
Reproduction Steps
- Upload an SVG containing the line
<?xml version="1.0" encoding="utf-8"?>at the top to a Payload collection. - Use an
<img />tag with thesrcset to the file URL. - Notice that the image fails to load on the page.
- Remove
<?xml version="1.0" encoding="utf-8"?>from the SVG file - SVG file loads without issue
Adapters and Plugins
No response
I'm having the same issues. Even with the Image Component from next i'm not able to display SVGs. Removal of "" fixes the issue for me aswell.
The media is saved with mimeType "image/svg+xml", but is served as content-type: application/xml (/api/media/file/<img>.svg)
This is due to the package file-type not supporting SVGs
(cf. https://www.npmjs.com/package/file-type)
This package is for detecting binary-based file formats, not text-based formats like .txt, .csv, .svg, etc.
It might not be an easy fix. It is worth mentioning that @payloadcms/storage-s3 does not have that issue (same goes with @payloadcms/plugin-cloud-storage if you're not on Payload 3.0 just yet).
Most production apps won't use on-disk storage anyway. And you can very easily have a Minio running locally if can't use an actual S3 bucket.
Blog post about Cloud storage: https://payloadcms.com/blog/plugin-cloud-storage
I hacked around this bug by adding this config to my media collection:
upload: {
modifyResponseHeaders({ headers }) {
if (headers.get('content-type') === 'application/xml') {
headers.set('content-type', 'image/svg+xml; charset=utf-8')
}
return headers
},
This might be available on v3 only, not sure about that.
@linobino1 Nice fix.
I'm guessing that it makes SVG work by breaking other XML files though. Uploads are mostly used for images, so it fixes the main use case, but it might not be clean enough to be merged.
You can still use this if your use case is image-only uploads (so most apps I would assume).
I also ran into this.
Using a plugin "fixed" it for me.
Thanks, @theo-lubert.
Yes same issue here, accessing the image url in the browser works fine, but curling it returns content-type: application/xml instead. @linobino1 fix works for my development environment, I'm using cloud storage only in production.
I saw that the upload logic has a specific condition to handle this,
https://github.com/payloadcms/payload/blob/8ace0cab339815627b48f43ee952684f04889ca6/packages/payload/src/uploads/generateFileData.ts#L206-L209
Perhaps we can also add one in the download logic.
https://github.com/payloadcms/payload/blob/8ace0cab339815627b48f43ee952684f04889ca6/packages/payload/src/collections/endpoints/getFile.ts#L58-L61
I am having the same issue
Hi, any news?
+1
Removing the xml tag fixes it for me too.. I guess a custom middleware that removes the tag would be perfect, but I'm new with payload so I don't know if it's possible
This issue has been automatically locked. Please open a new issue if this issue persists with any additional detail.