Catching IntegrityError

Hello!

How I can catch database error and throw it to frontend in JSON?

In DEBUG=True mode I get

Exception Type: IntegrityError
Exception Value: (‘23000’, ‘[23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]…Some MS SQL Server Exception…(547) (SQLExecDirectW); [23000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]The statement has been terminated. (3621)’)

But I can’t get this value in try/catch. e.message is empty.
So is it possible?

You could use an except in a middleware, probably quite high up in the chain.

I’ve tried to use process_exception() in middleware at any level, but exception message is empty everywhere.

Actually, I even can’t catch raise Exception("Test") message in middleware

I did a little bit of digging, and found out that this is known to happen under a couple of very specific circumstances. There appear to be some well known issues with PyODBC not throwing exceptions when the database transaction returns multiple results. So my initial conjecture is that there’s no exception for you to catch.

For some ideas, take a look at:
https://github.com/mkleehammer/pyodbc/issues/69 and
https://stackoverflow.com/questions/29377756/pyodbc-doesnt-report-sql-server-error
(Note: I searched for “django pyodbc sql server doesn’t throw exceptions”. That seems like a good place to start.)

These aren’t Django specific references, but identify that the issue may be lower down in the stack and are being caused outside what Django has control over. Without having more details about your specific environment (versions of code, SQL Server, statement throwing the error, etc) I can’t narrow it down any more than this.

If I were investigating this, I’d try to recreate it in the Django shell, and follow it from there.

@mikhail349 Here’s a demo of the middleware approach: https://github.com/adamchainz/django-demo-integrity-error-middleware

1 Like

Python 3.8.0
Django 2.1.15
pyodbc 4.0.30
MS SQL Server 2017

Notes: I don’t use any procedures, functions and etc. provided by MS SQL Server. I’m trying to get a native error from ms sql server - foreign key constraint. Pyodbc catches it and in debug mode shows me the value in debug page. But I don’t understand how I can get this value in view/middleware. Even if I raise simple exception in view I can’t catch it in middleware process_exception(). Exception comes (with correct class name) but withno value

That sounds like pyodbc might be doing raise IntegrityError instead of raise IntegrityError("some values") and just logging the value.

Please see my example project for a correctly working process_exception() which you can use to investigate that.

Thanks for example!

def process_exception(self, request, exception):
    if isinstance(exception, IntegrityError):
        return HttpResponse("😨 IntegrityError")

My code is equal but I’m trying to get smth like:

def process_exception(self, request, exception):
    if isinstance(exception, IntegrityError):
        return HttpResponse("IntegrityError: " + exception.message)

It might be the IntegrityError class from inside odbc rather than Django’s?