"Error uploading image with JavaScript client: Invalid image, could not read metadata"
This is a common issue when uploading images with the Sanity JavaScript client! The error "Invalid image, could not read metadata" typically occurs when you're passing a URL or incorrect data format to client.assets.upload() instead of the actual file data.
As you discovered, the problem was sending the BLOB via URL to the function. The Sanity client expects the actual File object or binary data, not a blob URL string created with URL.createObjectURL().
Here's the corrected approach:
export async function uploadImageBlob(blob: File, fileName: string) {
try {
// Pass the File object directly - NOT a URL
const result = await client.assets.upload('image', blob, {
contentType: blob.type || 'image/jpeg', // Use the actual file type
filename: fileName
});
console.log('Upload success:', result);
return result;
} catch (err) {
console.error('Upload error:', err);
throw err;
}
}Common causes of this error:
Passing a URL instead of the File object - If you create a blob URL with
URL.createObjectURL(blob)and pass that string to the upload function, it will fail. Always pass the actualFileobject.File type mismatch - Use
blob.typeto get the actual MIME type rather than hardcoding'image/jpeg'. This ensures the content type matches the actual file.Corrupted or invalid file - Ensure the file from React Dropzone is a valid image format that Sanity supports (JPEG, PNG, GIF, WebP, SVG, etc.).
Working example with React Dropzone:
import { useDropzone } from 'react-dropzone';
import { client } from './sanityClient';
function ImageUploader() {
const onDrop = async (acceptedFiles: File[]) => {
const file = acceptedFiles[0];
try {
// Pass the File object directly - NOT a URL
const asset = await client.assets.upload('image', file, {
contentType: file.type,
filename: file.name
});
console.log('Uploaded asset:', asset);
} catch (error) {
console.error('Upload failed:', error);
}
};
const { getRootProps, getInputProps } = useDropzone({
onDrop,
accept: {
'image/*': ['.jpeg', '.jpg', '.png', '.gif', '.webp']
}
});
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drop an image here</p>
</div>
);
}The key takeaway: never convert the File to a URL before passing it to client.assets.upload(). The method expects the raw file data, which the File object from React Dropzone provides directly. Thanks for sharing your solution - it'll definitely help others who encounter this same error!
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.