diff --git a/app/api/admin/users/[id]/route.ts b/app/api/admin/users/[id]/route.ts index ece7dc5..5f3637c 100644 --- a/app/api/admin/users/[id]/route.ts +++ b/app/api/admin/users/[id]/route.ts @@ -100,16 +100,21 @@ export async function DELETE( const admin = getSupabaseAdmin(); + // Confirm the user exists up front. GoTrue replies with an empty body when + // deleting a non-existent user, which supabase-js surfaces as an opaque + // JSON-parse error (no status / "not found" text); a positive existence + // check lets us return a clean 404 instead of a misleading 500. + const { data: existing, error: lookupErr } = + await admin.auth.admin.getUserById(id); + if (lookupErr || !existing.user) { + return jsonNoStore({ error: 'user not found' }, { status: 404 }); + } + // Delete the AUTH USER first. Only if that succeeds do we remove the tunnel // row, so a mid-failure never leaves an orphaned auth user with a dangling // tunnel (or half-deletes the tunnel of an already-gone user). const { error: delErr } = await admin.auth.admin.deleteUser(id); if (delErr) { - const httpStatus = (delErr as { status?: number }).status; - const message = (delErr.message ?? '').toLowerCase(); - if (httpStatus === 404 || message.includes('not found')) { - return jsonNoStore({ error: 'user not found' }, { status: 404 }); - } console.error('admin user.delete: deleteUser failed', delErr); return jsonNoStore({ error: 'internal error' }, { status: 500 }); }