Dashboard crashing, webhooks not receiving requests, and logs not showing on new project
@nipunn moving here to avoid cluttering #general
Event IDs:
417b3977e3774793bd7b334912920064
23087658685c40b599ac24e9e9a1173a
I think this might be happening after I try to hit my /clerk-users-webhook HTTP handler. It returns a 502 error on the Clerk dashboard and when I return to convex to check the logs, everything crashes until I refresh. This is a brand new project, webhook code:
schema:
import { httpRouter } from "convex/server"
import { httpAction } from "./_generated/server"
import { internal } from "./_generated/api"
import type { WebhookEvent } from "@clerk/backend"
import { Webhook } from "svix"
function ensureEnvironmentVariable() {
const value = process.env.CLERK_WEBHOOK_SECRET
if (value === undefined) {
throw new Error(`missing environment variable CLERK_WEBHOOK_SECRET`)
}
return value
}
const webhookSecret = ensureEnvironmentVariable()
const handleClerkWebhook = httpAction(async (ctx, request) => {
const event = await validateRequest(request)
if (!event) {
return new Response("Error occured", {
status: 400,
})
}
switch (event.type) {
case "user.created": // intentional fallthrough
case "user.updated": {
const existingUser = await ctx.runQuery(internal.users.getUser, {
subject: event.data.id,
})
if (existingUser && event.type === "user.created") {
console.warn("Overwriting user", event.data.id, "with", event.data)
}
console.log("creating/updating user", event.data.id)
await ctx.runMutation(internal.users.updateOrCreateUser, {
clerkUser: event.data,
})
break
}
case "user.deleted": {
// Clerk docs say this is required, but the types say optional?
const id = event.data.id!
await ctx.runMutation(internal.users.deleteUser, { id })
break
}
default: {
console.log("ignored Clerk webhook event", event.type)
}
}
return new Response(null, {
status: 200,
})
})
const http = httpRouter()
http.route({
path: "/clerk-users-webhook",
method: "POST",
handler: handleClerkWebhook,
})
async function validateRequest(
req: Request
): Promise<WebhookEvent | undefined> {
const payloadString = await req.text()
const svixHeaders = {
"svix-id": req.headers.get("svix-id")!,
"svix-timestamp": req.headers.get("svix-timestamp")!,
"svix-signature": req.headers.get("svix-signature")!,
}
const wh = new Webhook(webhookSecret)
let evt: Event | null = null
try {
evt = wh.verify(payloadString, svixHeaders) as Event
} catch (_) {
console.log("error verifying request")
return
}
return evt as unknown as WebhookEvent
}
export default http
import { httpRouter } from "convex/server"
import { httpAction } from "./_generated/server"
import { internal } from "./_generated/api"
import type { WebhookEvent } from "@clerk/backend"
import { Webhook } from "svix"
function ensureEnvironmentVariable() {
const value = process.env.CLERK_WEBHOOK_SECRET
if (value === undefined) {
throw new Error(`missing environment variable CLERK_WEBHOOK_SECRET`)
}
return value
}
const webhookSecret = ensureEnvironmentVariable()
const handleClerkWebhook = httpAction(async (ctx, request) => {
const event = await validateRequest(request)
if (!event) {
return new Response("Error occured", {
status: 400,
})
}
switch (event.type) {
case "user.created": // intentional fallthrough
case "user.updated": {
const existingUser = await ctx.runQuery(internal.users.getUser, {
subject: event.data.id,
})
if (existingUser && event.type === "user.created") {
console.warn("Overwriting user", event.data.id, "with", event.data)
}
console.log("creating/updating user", event.data.id)
await ctx.runMutation(internal.users.updateOrCreateUser, {
clerkUser: event.data,
})
break
}
case "user.deleted": {
// Clerk docs say this is required, but the types say optional?
const id = event.data.id!
await ctx.runMutation(internal.users.deleteUser, { id })
break
}
default: {
console.log("ignored Clerk webhook event", event.type)
}
}
return new Response(null, {
status: 200,
})
})
const http = httpRouter()
http.route({
path: "/clerk-users-webhook",
method: "POST",
handler: handleClerkWebhook,
})
async function validateRequest(
req: Request
): Promise<WebhookEvent | undefined> {
const payloadString = await req.text()
const svixHeaders = {
"svix-id": req.headers.get("svix-id")!,
"svix-timestamp": req.headers.get("svix-timestamp")!,
"svix-signature": req.headers.get("svix-signature")!,
}
const wh = new Webhook(webhookSecret)
let evt: Event | null = null
try {
evt = wh.verify(payloadString, svixHeaders) as Event
} catch (_) {
console.log("error verifying request")
return
}
return evt as unknown as WebhookEvent
}
export default http
import { defineSchema, defineTable } from "convex/server"
import { v } from "convex/values"
export default defineSchema({
users: defineTable({
// this is UserJSON from @clerk/backend
clerkUser: v.any(),
admin: v.optional(v.boolean()),
}).index("by_clerk_id", ["clerkUser.id"]),
})
import { defineSchema, defineTable } from "convex/server"
import { v } from "convex/values"
export default defineSchema({
users: defineTable({
// this is UserJSON from @clerk/backend
clerkUser: v.any(),
admin: v.optional(v.boolean()),
}).index("by_clerk_id", ["clerkUser.id"]),
})
2 Replies