Skip to content

Postgresql operations exception are not well handled

Summary

When SQLAlchemy ORM raise exception on database operation, PostgreSQL exception are not well handled

Steps to reproduce

  • Add the same email in the "Subscribe" section twice

What is the current bug behavior?

500 error

What is the expected correct behavior?

Should be handled correctly with in app try/except

Relevant logs and/or screenshots

[2022-07-15 09:00:14 +0200] [8] [ERROR] Exception on /notification/suscribe [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context
    self.dialect.do_execute(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "subscriber_email_key"
DETAIL:  Key (email)=(xxxx@example.fr) already exists.


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/app/ProdManager/helpers/resource.py", line 118, in create_resource
    db.session.commit()
  File "<string>", line 2, in commit
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 1451, in commit
    self._transaction.commit(_to_root=self.future)
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 829, in commit
    self._prepare_impl()
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 808, in _prepare_impl
    self.session.flush()
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3383, in flush
    self._flush(objects)
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3522, in _flush
    with util.safe_reraise():
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
    compat.raise_(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
    raise exception
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/session.py", line 3483, in _flush
    flush_context.execute()
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/unitofwork.py", line 456, in execute
    rec.execute(self)
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/unitofwork.py", line 630, in execute
    util.preloaded.orm_persistence.save_obj(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/persistence.py", line 245, in save_obj
    _emit_insert_statements(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/persistence.py", line 1238, in _emit_insert_statements
    result = connection._execute_20(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1631, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/sql/elements.py", line 332, in _execute_on_connection
    return connection._execute_clauseelement(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1498, in _execute_clauseelement
    ret = self._execute_context(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1862, in _execute_context
    self._handle_dbapi_exception(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 2043, in _handle_dbapi_exception
    util.raise_(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
    raise exception
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context
    self.dialect.do_execute(
  File "/usr/local/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "subscriber_email_key"
DETAIL:  Key (email)=(xxxx@example.fr) already exists.

[SQL: INSERT INTO subscriber (email) VALUES (%(email)s) RETURNING subscriber.id]
[parameters: {'email': 'xxxx@example.fr'}]
(Background on this error at: https://sqlalche.me/e/14/gkpj)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/app/ProdManager/routes/notification/views.py", line 35, in subscribe
    _ = create_resource(Subscriber, dict(
  File "/app/ProdManager/helpers/resource.py", line 125, in create_resource
    raise ServerError(error) from error
ProdManager.helpers.response.ServerError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "subscriber_email_key"
DETAIL:  Key (email)=(xxxx@example.fr) already exists.

[SQL: INSERT INTO subscriber (email) VALUES (%(email)s) RETURNING subscriber.id]
[parameters: {'email': 'xxxx@example.fr'}]
(Background on this error at: https://sqlalche.me/e/14/gkpj)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1523, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1509, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "/app/ProdManager/routes/notification/views.py", line 41, in subscribe
    return abort(error.code, dict(
  File "/usr/local/lib/python3.10/site-packages/werkzeug/exceptions.py", line 879, in abort
    _aborter(status, *args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/werkzeug/exceptions.py", line 862, in __call__
    raise self.mapping[code](*args, **kwargs)
werkzeug.exceptions.InternalServerError: 500 Internal Server Error: {'message': 'Abonnement aux notifications échoué', 'reasons': {'scope': [IntegrityError('(psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "subscriber_email_key"\nDETAIL:  Key (email)=(xxxx@example.fr) already exists.\n')]}}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 2077, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1525, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1384, in handle_user_exception
    return self.handle_http_exception(e)
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1324, in handle_http_exception
    return self.ensure_sync(handler)(e)
  File "/app/ProdManager/errors/server.py", line 5, in internal_error
    return render_template("error/500.html",
  File "/usr/local/lib/python3.10/site-packages/flask/templating.py", line 148, in render_template
    return _render(
  File "/usr/local/lib/python3.10/site-packages/flask/templating.py", line 128, in _render
    rv = template.render(context)
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/app/ProdManager/templates/error/500.html", line 3, in top-level template code
    {% set error_title = _("error_500") %}
  File "/app/ProdManager/templates/error/base.html", line 4, in top-level template code
    {% set share_title = _("error_title") %}
  File "/app/ProdManager/templates/base.html", line 86, in top-level template code
    {% block content %}{% endblock %}
  File "/app/ProdManager/templates/error/base.html", line 14, in block 'content'
    {{ attribute }} : {{ ",".join(reason) }}
TypeError: sequence item 0: expected str instance, IntegrityError found

Environment info

0.11.0

Possible fixes

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information