Reversing migrations which fire the pre_delete signal cause migration reversal to fail and leave DB in an inconsistent state #11617

Closed
opened 2025-12-29 21:47:42 +01:00 by adam · 2 comments
Owner

Originally created by @DanSheps on GitHub (Sep 16, 2025).

NetBox Edition

NetBox Community

NetBox Version

v4.4.0

Python Version

3.12

Steps to Reproduce

  1. Migrate to v4.4.0
  2. Reverse migration: dcim 0214_platform_rebuild

Expected Behavior

Migration reverses successfully

Observed Behavior

Exception is raised:


  File "C:\Development\netbox\venv\Lib\site-packages\django\db\migrations\executor.py", line 219, in _migrate_all_backwards
    self.unapply_migration(states[migration], migration, fake=fake)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\migrations\executor.py", line 287, in unapply_migration
    self.recorder.record_unapplied(migration.app_label, migration.name)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\migrations\recorder.py", line 107, in record_unapplied
    self.migration_qs.filter(app=app, name=name).delete()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 1199, in delete
    num_deleted, num_deleted_per_model = collector.delete()
                                         ~~~~~~~~~~~~~~~~^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\deletion.py", line 458, in delete
    signals.pre_delete.send(
    ~~~~~~~~~~~~~~~~~~~~~~~^
        sender=model,
        ^^^^^^^^^^^^^
    ...<2 lines>...
        origin=self.origin,
        ^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Development\netbox\venv\Lib\site-packages\django\dispatch\dispatcher.py", line 189, in send
    response = receiver(signal=self, sender=sender, **named)
  File "C:\Development\netbox\netbox\netbox\extras\signals.py", line 156, in notify_object_changed
    if not has_feature(instance, 'notifications'):
           ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Development\netbox\netbox\netbox\netbox\models\features.py", line 682, in has_feature
    ot = ObjectType.objects.get_for_model(model_or_ct)
  File "C:\Development\netbox\netbox\netbox\core\models\object_types.py", line 75, in get_for_model
    ot = self.get(app_label=opts.app_label, model=opts.model_name)
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 629, in get
    num = len(clone)
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 366, in __len__
    self._fetch_all()
    ~~~~~~~~~~~~~~~^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 1949, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
                         ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 91, in __iter__
    results = compiler.execute_sql(
        chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size
    )
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1623, in execute_sql
    cursor.execute(sql, params)
    ~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
    return super().execute(sql, params)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
    return self._execute_with_wrappers(
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        sql, params, many=False, executor=self._execute
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
    with self.db.wrap_database_errors:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)
           ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.InternalError: current transaction is aborted, commands ignored until end of transaction block
Originally created by @DanSheps on GitHub (Sep 16, 2025). ### NetBox Edition NetBox Community ### NetBox Version v4.4.0 ### Python Version 3.12 ### Steps to Reproduce 1. Migrate to v4.4.0 2. Reverse migration: `dcim 0214_platform_rebuild` ### Expected Behavior Migration reverses successfully ### Observed Behavior Exception is raised: ``` File "C:\Development\netbox\venv\Lib\site-packages\django\db\migrations\executor.py", line 219, in _migrate_all_backwards self.unapply_migration(states[migration], migration, fake=fake) ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\migrations\executor.py", line 287, in unapply_migration self.recorder.record_unapplied(migration.app_label, migration.name) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\migrations\recorder.py", line 107, in record_unapplied self.migration_qs.filter(app=app, name=name).delete() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 1199, in delete num_deleted, num_deleted_per_model = collector.delete() ~~~~~~~~~~~~~~~~^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\deletion.py", line 458, in delete signals.pre_delete.send( ~~~~~~~~~~~~~~~~~~~~~~~^ sender=model, ^^^^^^^^^^^^^ ...<2 lines>... origin=self.origin, ^^^^^^^^^^^^^^^^^^^ ) ^ File "C:\Development\netbox\venv\Lib\site-packages\django\dispatch\dispatcher.py", line 189, in send response = receiver(signal=self, sender=sender, **named) File "C:\Development\netbox\netbox\netbox\extras\signals.py", line 156, in notify_object_changed if not has_feature(instance, 'notifications'): ~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Development\netbox\netbox\netbox\netbox\models\features.py", line 682, in has_feature ot = ObjectType.objects.get_for_model(model_or_ct) File "C:\Development\netbox\netbox\netbox\core\models\object_types.py", line 75, in get_for_model ot = self.get(app_label=opts.app_label, model=opts.model_name) File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 629, in get num = len(clone) File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 366, in __len__ self._fetch_all() ~~~~~~~~~~~~~~~^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 1949, in _fetch_all self._result_cache = list(self._iterable_class(self)) ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\query.py", line 91, in __iter__ results = compiler.execute_sql( chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size ) File "C:\Development\netbox\venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1623, in execute_sql cursor.execute(sql, params) ~~~~~~~~~~~~~~^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute return super().execute(sql, params) ~~~~~~~~~~~~~~~^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute return self._execute_with_wrappers( ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ sql, params, many=False, executor=self._execute ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ) ^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers return executor(sql, params, many, context) File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute with self.db.wrap_database_errors: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Development\netbox\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value File "C:\Development\netbox\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute return self.cursor.execute(sql, params) ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ django.db.utils.InternalError: current transaction is aborted, commands ignored until end of transaction block ```
adam added the netbox label 2025-12-29 21:47:42 +01:00
adam closed this issue 2025-12-29 21:47:42 +01:00
Author
Owner

@DanSheps commented on GitHub (Sep 16, 2025):

As a test, --fake also produces the same issue

With:

@receiver(pre_delete)
def handle_deleted_object(sender, instance, **kwargs):
    if sender._meta.app_label == 'migrations':
        return

The migration is successful.

@DanSheps commented on GitHub (Sep 16, 2025): As a test, `--fake` also produces the same issue With: ``` @receiver(pre_delete) def handle_deleted_object(sender, instance, **kwargs): if sender._meta.app_label == 'migrations': return ``` The migration is successful.
Author
Owner

@jeremystretch commented on GitHub (Sep 18, 2025):

Reverse migration: dcim 0214_platform_rebuild

Reverse database migrations are not supported for any core application. There are many migrations within NetBox which will fail if attempted in reverse.

@jeremystretch commented on GitHub (Sep 18, 2025): > Reverse migration: dcim 0214_platform_rebuild Reverse database migrations are not supported for any core application. There are many migrations within NetBox which will fail if attempted in reverse.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11617