upgrade.sh Fails with "issubclass() arg 1 must be a class" #11733

Closed
opened 2025-12-29 21:49:13 +01:00 by adam · 4 comments
Owner

Originally created by @didorothy on GitHub (Oct 15, 2025).

Originally assigned to: @jnovinger on GitHub.

NetBox Edition

NetBox Community

NetBox Version

v4.4.3 (I'm actually running on the latest main branch in the repository)

Python Version

3.12

Steps to Reproduce

On an existing installation, run the upgrade.sh script and it throws the following exception:

... more above that is probably irrelevant ...
Finished.
Building documentation (mkdocs build)...
INFO    -  Cleaning site directory
INFO    -  Building documentation to directory: /home/ddorothy/apps/netbox.site/netbox/netbox/project-static/docs
INFO    -  Doc file 'development/models.md' contains a link '../features/customization.md#bookmarks', but the doc
           'features/customization.md' does not contain an anchor '#bookmarks'.
INFO    -  Documentation built in 8.74 seconds
Collecting static files (python3 netbox/manage.py collectstatic --no-input)...

416 static files copied to '/home/ddorothy/apps/netbox.site/netbox/netbox/static', 93 unmodified.
Removing stale content types (python3 netbox/manage.py remove_stale_contenttypes --no-input)...
No active configuration revision found - falling back to most recent
Traceback (most recent call last):
  File "/home/ddorothy/apps/netbox.site/netbox/netbox/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 416, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 460, in execute
    output = self.handle(*args, **options)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/contrib/contenttypes/management/commands/remove_stale_contenttypes.py", line 102, in handle
    ct.delete()
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 1281, in delete
    return collector.delete()
           ^^^^^^^^^^^^^^^^^^
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/db/models/deletion.py", line 458, in delete
    signals.pre_delete.send(
  File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/dispatch/dispatcher.py", line 189, in send
    response = receiver(signal=self, sender=sender, **named)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ddorothy/apps/netbox.site/netbox/netbox/extras/signals.py", line 152, in notify_object_changed
    if not has_feature(instance, 'notifications'):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ddorothy/apps/netbox.site/netbox/netbox/netbox/models/features.py", line 684, in has_feature
    return test_func(model)
           ^^^^^^^^^^^^^^^^
  File "/home/ddorothy/apps/netbox.site/netbox/netbox/netbox/models/features.py", line 643, in <lambda>
    register_model_feature('notifications', lambda model: issubclass(model, NotificationsMixin))
                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: issubclass() arg 1 must be a class

Expected Behavior

The upgrade.sh script should not throw an exception. I would expect if it was a problem with my installation it would give a different error message.

Observed Behavior

A TypeError was raised appearing to originate from line 152 in netbox/netbox/extras/signals.py

I bypassed the issue on my local copy by making the following change to that file:

diff --git a/netbox/extras/signals.py b/netbox/extras/signals.py
index 7105c38b4..39264201c 100644
--- a/netbox/extras/signals.py
+++ b/netbox/extras/signals.py
@@ -149,7 +149,7 @@ def notify_object_changed(sender, instance, **kwargs):
         event_type = OBJECT_DELETED

     # Skip unsupported object types
-    if not has_feature(instance, 'notifications'):
+    if not has_feature(instance.__class__, 'notifications'):
         return

     ct = ContentType.objects.get_for_model(instance)

Whether this is the right place for a change, I'm not sure but it seemed the easiest way to fix the problem.

Originally created by @didorothy on GitHub (Oct 15, 2025). Originally assigned to: @jnovinger on GitHub. ### NetBox Edition NetBox Community ### NetBox Version v4.4.3 (I'm actually running on the latest main branch in the repository) ### Python Version 3.12 ### Steps to Reproduce On an existing installation, run the upgrade.sh script and it throws the following exception: ``` ... more above that is probably irrelevant ... Finished. Building documentation (mkdocs build)... INFO - Cleaning site directory INFO - Building documentation to directory: /home/ddorothy/apps/netbox.site/netbox/netbox/project-static/docs INFO - Doc file 'development/models.md' contains a link '../features/customization.md#bookmarks', but the doc 'features/customization.md' does not contain an anchor '#bookmarks'. INFO - Documentation built in 8.74 seconds Collecting static files (python3 netbox/manage.py collectstatic --no-input)... 416 static files copied to '/home/ddorothy/apps/netbox.site/netbox/netbox/static', 93 unmodified. Removing stale content types (python3 netbox/manage.py remove_stale_contenttypes --no-input)... No active configuration revision found - falling back to most recent Traceback (most recent call last): File "/home/ddorothy/apps/netbox.site/netbox/netbox/manage.py", line 10, in <module> execute_from_command_line(sys.argv) File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line utility.execute() File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 416, in run_from_argv self.execute(*args, **cmd_options) File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 460, in execute output = self.handle(*args, **options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/contrib/contenttypes/management/commands/remove_stale_contenttypes.py", line 102, in handle ct.delete() File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 1281, in delete return collector.delete() ^^^^^^^^^^^^^^^^^^ File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/db/models/deletion.py", line 458, in delete signals.pre_delete.send( File "/home/ddorothy/apps/netbox.site/netbox/venv/lib/python3.12/site-packages/django/dispatch/dispatcher.py", line 189, in send response = receiver(signal=self, sender=sender, **named) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ddorothy/apps/netbox.site/netbox/netbox/extras/signals.py", line 152, in notify_object_changed if not has_feature(instance, 'notifications'): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/ddorothy/apps/netbox.site/netbox/netbox/netbox/models/features.py", line 684, in has_feature return test_func(model) ^^^^^^^^^^^^^^^^ File "/home/ddorothy/apps/netbox.site/netbox/netbox/netbox/models/features.py", line 643, in <lambda> register_model_feature('notifications', lambda model: issubclass(model, NotificationsMixin)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: issubclass() arg 1 must be a class ``` ### Expected Behavior The upgrade.sh script should not throw an exception. I would expect if it was a problem with my installation it would give a different error message. ### Observed Behavior A TypeError was raised appearing to originate from line [152 in netbox/netbox/extras/signals.py](https://github.com/netbox-community/netbox/blob/main/netbox/extras/signals.py#L152) I bypassed the issue on my local copy by making the following change to that file: ``` diff --git a/netbox/extras/signals.py b/netbox/extras/signals.py index 7105c38b4..39264201c 100644 --- a/netbox/extras/signals.py +++ b/netbox/extras/signals.py @@ -149,7 +149,7 @@ def notify_object_changed(sender, instance, **kwargs): event_type = OBJECT_DELETED # Skip unsupported object types - if not has_feature(instance, 'notifications'): + if not has_feature(instance.__class__, 'notifications'): return ct = ContentType.objects.get_for_model(instance) ``` Whether this is the right place for a change, I'm not sure but it seemed the easiest way to fix the problem.
adam added the type: bugstatus: acceptedseverity: high labels 2025-12-29 21:49:13 +01:00
adam closed this issue 2025-12-29 21:49:14 +01:00
Author
Owner

@bevand10 commented on GitHub (Oct 15, 2025):

Hi David - snap! https://github.com/netbox-community/netbox/issues/20588

Was yours a clean install too? I found a commit from last week that changed the behaviour of this part of the code - not signals which seems more in the core and is probably a widely shared/used feature.

@bevand10 commented on GitHub (Oct 15, 2025): Hi David - snap! https://github.com/netbox-community/netbox/issues/20588 Was yours a clean install too? I found a commit from last week that changed the behaviour of this part of the code - not signals which seems more in the core and is probably a widely shared/used feature.
Author
Owner

@didorothy commented on GitHub (Oct 15, 2025):

It was not a fresh install. I have several bits of data stored about a local network. I have since reverted the code change I made locally and run the upgrade.sh script again and there are no failures so it must have something to do with updating existing records that once updated does not cause the problem to repeat. However, this probably means that the issue could recur at a future update if the signal is again triggered.

I followed the exception stack trace up to the netbox/netbox/extras/signals.py file. So it appears that the code in netbox/netbox/netbox/models/features.py where the exception occurred requires that a class object is passed. However, in the netbox/netbox/extras/signals.py it is passing an instance of a Model class. What I was not sure about was whether the has_feature() function should be checking if a Model instance is passed to it and convert it to a class before passing it to the test function that was registered with register_model_feature() on line 643 in netbox/netbox/netbox/models/features.py. I'm not super familiar with this code base but I really like the tool.

If I've given too much info I apologize.

@didorothy commented on GitHub (Oct 15, 2025): It was not a fresh install. I have several bits of data stored about a local network. I have since reverted the code change I made locally and run the `upgrade.sh` script again and there are no failures so it must have something to do with updating existing records that once updated does not cause the problem to repeat. However, this probably means that the issue could recur at a future update if the signal is again triggered. I followed the exception stack trace up to the `netbox/netbox/extras/signals.py` file. So it appears that the code in `netbox/netbox/netbox/models/features.py` where the exception occurred requires that a class object is passed. However, in the `netbox/netbox/extras/signals.py` it is passing an instance of a Model class. What I was not sure about was whether the `has_feature()` function should be checking if a `Model` instance is passed to it and convert it to a class before passing it to the test function that was registered with `register_model_feature()` on line [643 in netbox/netbox/netbox/models/features.py](https://github.com/netbox-community/netbox/blob/main/netbox/netbox/models/features.py#L643). I'm not super familiar with this code base but I really like the tool. If I've given too much info I apologize.
Author
Owner

@jnovinger commented on GitHub (Oct 15, 2025):

@didorothy , appreciate all the extra eyes! Thank you.

I've been looking at this too. I believe it may be stemming from the change to has_feature() in 5ceb6a60da, which is what is calling the test_func() lambda test function defined on line 643. In theory, it should be sending a model class, as evidenced by the model = model_or_ct.model_class() call on line 678.

Still digging and trying to understand exactly what's happening.

Update: I've been able to reproduce this with a simpler set of steps (for a development env):

  • Checkout v4.4.2, install backend dependencies
  • Install v4.4 demo data from netbox-demo-data (just to not have to run all the migrations)
  • Create a fake stale ContentType instance, from a still installed app but a removed model
  • Checkout v4.4.3, install updated backend dependencies
  • Run migrations (may or may not be required)
  • Run `./manage.py remove_stale_contenttypes

I'll link a gist with a script to reproduce this after I clean it up.

@jnovinger commented on GitHub (Oct 15, 2025): @didorothy , appreciate all the extra eyes! Thank you. I've been looking at this too. I believe it may be stemming from the change to `has_feature()` in 5ceb6a60da2f862169ad0d9aca99b6c0daee910c, which is what is calling the `test_func()` lambda test function defined on line 643. In theory, it should be sending a model class, as evidenced by the `model = model_or_ct.model_class()` call on line 678. Still digging and trying to understand exactly what's happening. Update: I've been able to reproduce this with a simpler set of steps (for a development env): - Checkout v4.4.2, install backend dependencies - Install v4.4 demo data from netbox-demo-data (just to not have to run all the migrations) - Create a fake stale `ContentType` instance, from a still installed app but a removed model - Checkout v4.4.3, install updated backend dependencies - Run migrations (may or may not be required) - Run `./manage.py remove_stale_contenttypes I'll link a gist with a script to reproduce this after I clean it up.
Author
Owner

@jnovinger commented on GitHub (Oct 15, 2025):

Reproduction script: https://gist.github.com/jnovinger/35948fc653c0425a5f9b207f9b77883f

@jnovinger commented on GitHub (Oct 15, 2025): Reproduction script: https://gist.github.com/jnovinger/35948fc653c0425a5f9b207f9b77883f
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11733