Issue with stuck files in upload state resolved by deleting them via CLI in Sanity Studio 3.14.3.
This is a frustrating issue with stuck file uploads! The error you're seeing ("undefined is not an object (evaluating 'uploadState.file.name')") means your file documents have an incomplete or corrupted uploadState object. The fact that downloads work from the frontend confirms the actual asset files are in Sanity's CDN—it's just the Studio metadata that's broken.
Understanding What's Happening
Your files are stuck in a limbo state where the upload never fully completed, but the asset references still exist in your dataset. This is why you can't delete them through the normal Studio interface—Sanity sees the references and blocks deletion to maintain data integrity.
Solutions to Try
Option 1: Clean the Upload State (Recommended First Step)
The safest approach is to patch the documents to remove the corrupted uploadState while keeping the actual assets. You can do this with a script using the Sanity Client:
import {createClient} from '@sanity/client'
const client = createClient({
projectId: 'your-project-id',
dataset: 'your-dataset',
token: 'your-write-token', // Must have write permissions
apiVersion: '2023-05-03',
useCdn: false
})
async function cleanStuckUploads() {
// Find assets with incomplete upload state
const stuckAssets = await client.fetch(
`*[_type in ['sanity.imageAsset', 'sanity.fileAsset'] && defined(uploadId)]`
)
console.log(`Found ${stuckAssets.length} stuck uploads`)
for (const asset of stuckAssets) {
try {
await client
.patch(asset._id)
.unset(['uploadId', 'uploadState'])
.commit()
console.log(`✓ Cleaned ${asset._id}`)
} catch (err) {
console.error(`✗ Failed to clean ${asset._id}:`, err.message)
}
}
}
cleanStuckUploads()This removes the broken upload metadata while preserving the actual asset files and their references.
Option 2: Use the Mutation API to Delete
If you need to actually delete the assets (after handling references), you can use the HTTP Mutation API directly:
curl -X POST 'https://YOUR_PROJECT_ID.api.sanity.io/v2021-06-07/data/mutate/YOUR_DATASET' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"mutations": [
{"delete": {"id": "image-ASSET_ID"}}
]
}'Option 3: Find and Update References First
If you want to completely remove the assets, you'll need to handle references first. Find what's referencing them:
*[references('image-YOUR_ASSET_ID')]Then either update those documents to remove the reference or delete them if they're no longer needed. Only after removing all references will deletion succeed.
Option 4: Use the Client API for Deletion
You can also use the Sanity Client for deletions:
// Delete a specific asset (after removing references)
await client.delete('image-ASSET_ID')
// Or delete multiple assets
await client.delete(['asset-id-1', 'asset-id-2'])Note that this will fail if there are active references to the assets—you must handle those first.
Prevention Tips
To avoid this in the future:
Check your metadata configuration - Based on similar issues in the community, invalid metadata options can cause upload problems. The fields
dimensions,hasAlpha, andisOpaqueare always included automatically and should NOT be specified in your schema'smetadataarray. Only use:exif,location,lqip,blurhash, andpalette.Update Sanity Studio - Make sure you're on the latest version, as newer releases handle edge cases better.
Add error handling - Implement
onUploadCompleteandonUploadErrorcallbacks in your file field configuration to catch issues early.
Quick Diagnostic Query
First, identify exactly what you're dealing with:
// Find stuck uploads
*[_type in ['sanity.imageAsset', 'sanity.fileAsset'] && defined(uploadId)] {
_id,
uploadId,
url
}Start with Option 1 (cleaning the upload state) since it's the least destructive and should resolve the Studio errors while keeping your working assets intact. Good luck! 🙂
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.