
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThe 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:
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 });
}
}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);
};bodyParser: falsefs.createReadStream(file.filepath) to read the temp filefiles.image or files.filefiles.image[0] instead of files.imageAccording 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
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store