Script Valley
Next.js: Full-Stack React Applications
Database Integration with PrismaLesson 4.5

How to handle database errors and transactions in Prisma

Prisma error types, PrismaClientKnownRequestError, error codes, unique constraint handling, transactions, interactive transactions, rollback

Handling Known Errors

Prisma throws typed errors. Import the error class to handle specific cases:

import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'

export async function createUser(email: string) {
  try {
    return await prisma.user.create({ data: { email } })
  } catch (e) {
    if (e instanceof PrismaClientKnownRequestError) {
      if (e.code === 'P2002') {
        // Unique constraint violation
        return { error: 'Email already exists' }
      }
      if (e.code === 'P2025') {
        // Record not found (for update/delete)
        return { error: 'User not found' }
      }
    }
    throw e  // Re-throw unexpected errors
  }
}

Transactions

Use prisma.$transaction when multiple operations must succeed or fail together:

// Transfer credits between users
await prisma.$transaction(async (tx) => {
  const sender = await tx.user.update({
    where: { id: senderId },
    data: { credits: { decrement: amount } },
  })

  if (sender.credits < 0) {
    throw new Error('Insufficient credits')  // Triggers rollback
  }

  await tx.user.update({
    where: { id: receiverId },
    data: { credits: { increment: amount } },
  })
})

Interactive transactions receive a tx client — use it for all queries inside the callback. Throwing any error inside the callback automatically rolls back all changes. Never use the regular prisma client inside a transaction callback.