From 2ae98f0353e151f38a256a028de55f3711ef2071 Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Wed, 15 Oct 2025 12:27:14 -0500 Subject: [PATCH] Fixes #20587: Handle stale ContentTypes in has_feature() When deleting stale ContentTypes during remove_stale_contenttypes, the pre_delete signal triggers notify_object_changed(), which calls has_feature() with the ContentType instance. For stale types (those with no corresponding model class), model_class() returns None, which then gets passed to issubclass() in the feature test lambda, causing a TypeError. The previous implementation in has_feature() checked for None before attempting ObjectType lookup. The optimization in 5ceb6a6 removed this safety check when refactoring the ContentType code path to use direct feature registry lookups. This restores the null check to maintain the original behavior of returning False for stale ContentTypes. --- netbox/netbox/models/features.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index be58d647a..e0d03d6e7 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -676,6 +676,8 @@ def has_feature(model_or_ct, feature): # If a ContentType was passed, resolve its model class and run the associated feature test elif type(model_or_ct) is ContentType: model = model_or_ct.model_class() + if model is None: # Stale content type + return False try: test_func = registry['model_features'][feature] except KeyError: