The events.updateEvent mutation modifies an existing event’s information including name, description, location, date, price, and ticket capacity.
Function Signature
export const updateEvent = mutation({
args: {
eventId: v.id("events"),
name: v.string(),
description: v.string(),
location: v.string(),
eventDate: v.number(),
price: v.number(),
totalTickets: v.number(),
},
handler: async (ctx, args) => {
const { eventId, ...updates } = args;
// Get current event to check tickets sold
const event = await ctx.db.get(eventId);
if (!event) throw new Error("Event not found");
const soldTickets = await ctx.db
.query("tickets")
.withIndex("by_event", (q) => q.eq("eventId", eventId))
.filter((q) =>
q.or(q.eq(q.field("status"), "valid"), q.eq(q.field("status"), "used"))
)
.collect();
// Ensure new total tickets is not less than sold tickets
if (updates.totalTickets < soldTickets.length) {
throw new Error(
`Cannot reduce total tickets below ${soldTickets.length} (number of tickets already sold)`
);
}
await ctx.db.patch(eventId, updates);
return eventId;
},
});
Source: convex/events.ts:431-466
Parameters
The unique identifier of the event to update.Example: "k17abc123def456789"
The updated name of the event.Example: "Summer Music Festival 2026 - Updated"
The updated description of the event.Example: "Join us for an extended evening of live music featuring top local and international artists"
The updated location where the event will take place.Example: "Madison Square Garden, New York, NY"
The updated event date and time as a Unix timestamp in milliseconds.Example: 1752624000000
The updated price per ticket in dollars.Example: 55.00You can change the price at any time. Previously sold tickets retain their original purchase price.
The updated total number of tickets available.Example: 750Cannot be less than the number of tickets already sold (valid or used status).
Returns
The ID of the updated event (same as the input eventId).
Request Example
import { useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
function EditEventForm({ initialData }) {
const updateEvent = useMutation(api.events.updateEvent);
const handleSubmit = async (formData) => {
try {
await updateEvent({
eventId: initialData._id,
name: formData.name,
description: formData.description,
location: formData.location,
eventDate: formData.eventDate.getTime(),
price: formData.price,
totalTickets: formData.totalTickets,
});
toast.success("Event updated successfully");
router.push(`/event/${initialData._id}`);
} catch (error) {
console.error("Failed to update event:", error);
toast.error(error.message || "Failed to update event");
}
};
}
Source: src/components/event-form.tsx:138-142
Response Example
// Returns the event ID
"k17abc123def456789"
Validation & Constraints
Critical Constraint - Ticket CapacityThe totalTickets field cannot be reduced below the number of tickets already sold. The mutation will throw an error if you attempt to do so.// Example error:
"Cannot reduce total tickets below 150 (number of tickets already sold)"
Validation Rules
- eventId: Must reference an existing event
- name: Cannot be empty
- description: Cannot be empty
- location: Cannot be empty
- eventDate: Must be a valid number (timestamp)
- price: Must be 0 or greater
- totalTickets: Must be >= number of sold tickets (valid + used status)
Common Errors
Event Not Found
// Error thrown when eventId doesn't exist
"Event not found"
Ticket Capacity Too Low
// Error thrown when trying to reduce capacity below sold tickets
"Cannot reduce total tickets below 250 (number of tickets already sold)"
Example scenario:
// Current state: 250 tickets sold out of 500 total
const soldCount = 250;
const currentTotal = 500;
// This will fail:
await updateEvent({
eventId,
totalTickets: 200, // ❌ Less than 250 sold
// ... other fields
});
// This will succeed:
await updateEvent({
eventId,
totalTickets: 750, // ✅ Greater than 250 sold
// ... other fields
});
Use Cases
Increasing Ticket Capacity
// Add more tickets to an event
await updateEvent({
eventId: event._id,
name: event.name,
description: event.description,
location: event.location,
eventDate: event.eventDate,
price: event.price,
totalTickets: 1000, // Increased from 500
});
Updating Event Details
// Change venue and date
await updateEvent({
eventId: event._id,
name: event.name,
description: "Updated description with new details",
location: "New Venue - Convention Center Hall B",
eventDate: new Date("2026-08-15").getTime(), // New date
price: event.price,
totalTickets: event.totalTickets,
});
Changing Pricing
// Update ticket price for remaining tickets
await updateEvent({
eventId: event._id,
name: event.name,
description: event.description,
location: event.location,
eventDate: event.eventDate,
price: 65.00, // Increased from $45
totalTickets: event.totalTickets,
});
Price changes only affect new ticket purchases. Previously purchased tickets retain their original price.
Checking Sold Tickets Before Update
To safely update ticket capacity, first check how many tickets have been sold:
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
function EventEditor({ eventId }) {
const availability = useQuery(api.events.getEventAvailability, { eventId });
const updateEvent = useMutation(api.events.updateEvent);
const handleCapacityChange = async (newTotal: number) => {
if (!availability) return;
const soldCount = availability.purchasedCount;
if (newTotal < soldCount) {
toast.error(
`Cannot reduce capacity below ${soldCount} tickets (already sold)`
);
return;
}
await updateEvent({
eventId,
totalTickets: newTotal,
// ... other required fields
});
};
}
Related: convex/events.ts:448-455
Updating Event Images
Event images are managed separately through the Storage API:
import { api } from "../convex/_generated/api";
const updateEventImage = useMutation(api.storage.updateEventImage);
// After updating event details
if (newImageStorageId) {
await updateEventImage({
eventId,
storageId: newImageStorageId,
});
}
Source: src/components/event-form.tsx:144-153
Error Handling Best Practices
try {
await updateEvent({
eventId: event._id,
...updates,
});
toast.success("Event updated", {
description: "Your event has been successfully updated.",
});
router.push(`/event/${event._id}`);
} catch (error) {
console.error("Failed to update event:", error);
// Handle specific error cases
if (error.message?.includes("Cannot reduce total tickets")) {
toast.error("Ticket capacity error", {
description: error.message,
});
} else if (error.message === "Event not found") {
toast.error("Event not found", {
description: "This event may have been deleted.",
});
} else {
toast.error("Update failed", {
description: "There was a problem updating your event.",
});
}
}
Best Practices
- Fetch current event data before updating to populate the form
- Check sold ticket count before reducing capacity
- Validate all fields client-side before submission
- Provide clear error messages when updates fail
- Consider notification to ticket holders for major changes (date, location)
- Keep audit trail of significant changes for customer support