Upload multipart/form-data image to Sanity: "unsupported image format" error
The issue you're encountering happens because formidable returns a file object, but client.assets.upload() expects the actual file data (a stream, buffer, or File object). Here's how to fix it:
Solution 1: Using formidable with file streams (Recommended for your setup)
Since you're already using formidable, you need to read the actual file from the temporary path formidable creates:
import fs from 'fs';
import formidable from 'formidable';
import {client} from './sanityClient'; // your sanity client
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(req, res) {
const form = formidable();
try {
const [fields, files] = await form.parse(req);
// formidable v3+ returns arrays
const file = files.image?.[0] || files.file?.[0];
if (!file) {
return res.status(400).json({ error: 'No file uploaded' });
}
// Create a read stream from the temporary file
const fileStream = fs.createReadStream(file.filepath);
const asset = await client.assets.upload('image', fileStream, {
filename: file.originalFilename,
});
res.status(200).json({ _id: asset._id });
} catch (err) {
console.error('Upload error:', err);
res.status(400).json({ error: err.message });
}
}Solution 2: Using raw body (simpler approach)
If you don't need formidable's features, you can send the file as a raw body:
Backend:
import {client} from './sanityClient';
import getRawBody from 'raw-body';
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(req, res) {
try {
const rawBody = await getRawBody(req);
const asset = await client.assets.upload('image', rawBody, {
contentType: req.headers['content-type'] || 'image/jpeg',
filename: req.headers['x-filename'] || 'uploaded-image.jpg',
});
res.status(200).json({ _id: asset._id });
} catch (err) {
console.error('Upload error:', err);
res.status(400).json({ error: err.message });
}
}Frontend:
const handleSubmit = async (e) => {
e.preventDefault();
const file = e.target[0].files[0];
const arrayBuffer = await file.arrayBuffer();
const response = await fetch('/api/uploadImage', {
method: 'POST',
body: arrayBuffer,
headers: {
'Content-Type': file.type,
'X-Filename': file.name,
},
});
const data = await response.json();
console.log(data);
};Key Points:
- Always disable Next.js body parser with
bodyParser: false - With formidable: Use
fs.createReadStream(file.filepath)to read the temp file - File field name: Make sure your form field name matches what you're accessing in
files.imageorfiles.file - Formidable version: v3+ returns arrays, so use
files.image[0]instead offiles.image
According to the official Sanity documentation on uploading assets, client.assets.upload() accepts streams, buffers, or File objects - but not formidable's file descriptor objects directly.
Install raw-body if using Solution 2: npm install raw-body
Show original thread64 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.