prisma: Help developers better handle SQL errors

Problem

We sometimes want to handle SQL errors differently to return a proper error to the frontend. For example, we might want to display email already used if a unique violation is detected on the field. The current situation is that we have to check against an obscure error code (P2002 for example for unique validation failure) and then go into meta.target to get which field broke. Its never easy to extract meaningful stuff from ORM(-like) tools despite being a very common operation and I think it could be a factor of differentiation for prisma.

Propositions

I see two possible way of dealing more gracefully with that:

  1. Create more custom error types in javascript and use instanceof to catch them. This would look like:
      try {
        const user = await prisma.user.create({ data });
        return res.status(204).send();
      } catch (err) {
        if (err instanceof PrismaUniqueViolationError) {
          return res.status(400).send('DUPLICATE EMAIL');
        }
        return res.status(400).send('BAD REQUEST');
      }
    
  2. Create an enum of errors. This would look like
      try {
        const user = await prisma.user.create({ data });
        return res.status(204).send();
      } catch (err) {
        if (err.code === PrismaErrors.UniqueViolation) {
          return res.status(400).send('DUPLICATE EMAIL');
        }
        return res.status(400).send('BAD REQUEST');
      }
    

I also think there should be helpers to extract the problematic fields from the error. Something like:

if (err.code === PrismaErrors.UniqueViolation) {
    const duplicateFields = extractErrorFields(err);
    return res.status(400).json({ code: 'unique_violation', fields: duplicateFields});
}

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 166
  • Comments: 19 (6 by maintainers)

Most upvoted comments

If possible, I’d like to have something like this which I’ve initially proposed in prisma/prisma-client-js#720:

try {
  await db.users.insert(newUser)
} catch (err) {
  if (err instanceof UniqueConstraintViolation) {
    // not sure if typescript can infer the error, but I think it can
    if (err.field == "email") {
      console.log("user already exists with this email")
      return
    }
    console.log("unique constraint violation on another field: " + err.field)
  }
}

Any updates on the status of this?

I published a package to handle this feature https://github.com/vinpac/prisma-error-enum.

I can make a PR to integrate this into prisma. Should I?

import { PrismaError } from 'prisma-error-enum'

if (error.code === PrismaError.UniqueConstraintViolation)

I thought on an another solution that I may publish too.

const QueryError = {
  UniqueConstraintViolation: 'P2002'
} as const

interface UniqueConstraintViolation {
  code: 'P2002',
  meta: {
    target: string[]
  }
}

function isUniqueConstraintViolation(error: { code: string }): error is UniqueConstraintViolation {
  return error.code === QueryError.UniqueConstraintViolation
}

if (isUniqueConstraintViolation(error)) {
  // error is infered as UniqueConstraintViolation
 // so error.meta.target is an array
}

The query engine now adds more detailed error types. The next step will be to add the client side implementation.

My comments on this original issue:

  • I suggest this issue name be changed to include all prisma errors, not just SQL errors.
  • I think adding an error.code property is a good idea
  • I think any extra error information should be put directly on the error object in a way that doesn’t require a helper method to extract.

I see meta is still typed as an object. Are there any plans to add target to it in the interface ?

Thanks for looking into it @vinpac! We are looking into this right now already, so I fear that your package will then be obsolete. Until then, definitely good work! We need at least one sprint (2 weeks) to get a solution out but will notify you once we have something.

any updates on this?

With client version 3.8.1 the error.meta.target property contains the field name.

Are there any plans to also have the regarding table name in there? I would really appreciate it, since it also helps narrow down and improve an eroor message.

Also the meta object is of type object, at least in the version I’m using. Having this typed would also be awesome 😄

Below is the content of https://github.com/prisma/prisma/issues/2122 which I opened after this issue (I didn’t find this issue by searching for “error messages”)

Problem

  1. There is currently no easy way to handle different types of errors thrown by prisma client.
    • Currently it appears that all errors thrown by prisma client have error.name = 'Error'
  2. The content of error.message can vary a lot depending on the configured errorFormat. This makes it hard to consistently handle messages.
  3. There is no way to know all the possible errors that will be thrown

Solution

  1. All errors thrown by prisma client should have a descriptive name
  2. Add a field on all errors that always have a minimal error format regardless of the errorFormat config.
    • Example: error.shortMessage
  3. All possible errors should be clearly documented

Examples

error.name === 'PrismaInputError'
error.shortMessage === 'Argument where of type ProductWhereUniqueInput needs at least one argument'
error.message === " /* ... long error message ... */"
error.name === 'PrismaConnectionError'
error.shortMessage === 'Failed to connect to database blah blah'
error.message === " /* ... long error message ... */"
error.name === 'PrismaDatabaseViolation'
error.shortMessage === 'unique constraint violated, id = 1 already exists, blah blah'
error.message === " /* ... long error message ... */"

Hey, does someone have any updated on this?