File validation and deletion
Enforce file policy, prevent orphans, and delete storage with product metadata safely.
A secure file workflow covers the storage object and the product document that references it.
Validation stages
| Stage | Purpose |
|---|---|
| Browser size/type check | Fast UX feedback (maxSize, allowedTypes) |
| Authorized upload-URL mutation | Decide who may begin an upload |
| Server/content validation | Verify actual bytes and product policy |
| Metadata mutation | Associate storage ID with an authorized resource |
Never trust file extension or browser MIME type as the security decision.
Prevent orphans
An upload can succeed before metadata creation fails. Choose an explicit strategy:
- delete the new storage object in compensation;
- create a pending upload record before bytes are sent;
- run a bounded cleanup job for unattached uploads.
The module does not do this for you. When you record the file with the complete option of useConvexFileUpload, an error with phase: 'complete' means that the file was stored but may not be recorded. See Upload files.
Authorized deletion
import { ConvexError, v } from 'convex/values'
import { mutation } from './_generated/server'
import { auth } from './auth'
export const removeFile = mutation({
args: { documentId: v.id('documents') },
handler: async (ctx, args) => {
const user = await auth.requireUser(ctx)
const document = await ctx.db.get(args.documentId)
if (!document || document.ownerId !== user.id) {
throw new ConvexError({ code: 'DOCUMENT_NOT_FOUND' })
}
if (document.storageId) {
await ctx.storage.delete(document.storageId)
}
await ctx.db.patch(document._id, { storageId: undefined })
},
})Authorize by the product document, not by accepting an arbitrary storage ID from the browser.
Processing untrusted files
Use a controlled action or external scanning service for formats that require inspection. Record processing status in Convex so the UI can observe pending, accepted, or rejected state with a query.
Do not publish the storage URL until validation finishes when the product's threat model requires quarantine.