Upload multipart/form-data image to Sanity: "unsupported image format" error

64 replies
Last updated: Jan 17, 2026
how to upload mutlipart/form-data image in sanity cdn, I'm getting input buffer contains unsupported image format error. Below is my code-
export const config = {

api: {

bodyParser: false,

},

};


export default async function handler(

req: NextApiRequest,

res: NextApiResponse

) {

const data = await new Promise((resolve, reject) => {

const form = formidable();

form.parse(req, (err, fields, files) => {

if (err) {

reject(err);

}

resolve({ req, fields, files });

});

});

const { fields, files } = data;


try {

const { _id } = await client.assets.upload("image", files);

res.status(200).json(_id);

} catch (err) {

res.status(400).send(err);

}

}
AI Update

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:

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:

  1. Always disable Next.js body parser with bodyParser: false
  2. With formidable: Use fs.createReadStream(file.filepath) to read the temp file
  3. File field name: Make sure your form field name matches what you're accessing in files.image or files.file
  4. Formidable version: v3+ returns arrays, so use files.image[0] instead of files.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 thread
64 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.

Was this answer helpful?