Upgrade from v3.7.8 to v4.4.0 fails on migration users.0005_alter_user_table (core_objecttype missing) #11586

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

Originally created by @pheus on GitHub (Sep 7, 2025).

Originally assigned to: @jnovinger on GitHub.

Deployment Type

Self-hosted

NetBox Version

v4.4.0

Python Version

3.10

Steps to Reproduce

  1. Start with a fresh PostgreSQL database (no existing NetBox tables).
  2. Clone the NetBox repository and check out v3.7.8:
    git clone https://github.com/netbox-community/netbox.git /opt/netbox
    cd /opt/netbox
    git checkout v3.7.8
    
  3. Configure NetBox per the installation guide (minimal config with DB/Redis and ALLOWED_HOSTS) and initialize using the provided script:
    ./upgrade.sh
    
  4. Upgrade the working tree to v4.4.0:
    git checkout v4.4.0
    
  5. Run the upgrade script again to apply migrations for v4.4.0:
    ./upgrade.sh
    

Expected Behavior

The upgrade should complete successfully. All migrations should apply without errors and NetBox should start normally on v4.4.0.

Observed Behavior

The migration fails while applying users.0005_alter_user_table with an error indicating that core_objecttype does not exist:

Applying users.0005_alter_user_table...Traceback (most recent call last):
  File "/opt/netbox/venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/netbox-/venv/lib/python3.10/site-packages/psycopg/cursor.py", line 97, in execute
    raise ex.with_traceback(None)
psycopg.errors.UndefinedTable: relation "core_objecttype" does not exist
LINE 1: ...type"."public", "core_objecttype"."features" FROM "core_obje...
                                            ^

After this exception, the upgrade process aborts.

Originally created by @pheus on GitHub (Sep 7, 2025). Originally assigned to: @jnovinger on GitHub. ### Deployment Type Self-hosted ### NetBox Version v4.4.0 ### Python Version 3.10 ### Steps to Reproduce 1. Start with a fresh PostgreSQL database (no existing NetBox tables). 2. Clone the NetBox repository and check out **v3.7.8**: ~~~bash git clone https://github.com/netbox-community/netbox.git /opt/netbox cd /opt/netbox git checkout v3.7.8 ~~~ 3. Configure NetBox per the installation guide (minimal config with DB/Redis and `ALLOWED_HOSTS`) and initialize using the provided script: ~~~bash ./upgrade.sh ~~~ 4. Upgrade the working tree to **v4.4.0**: ~~~bash git checkout v4.4.0 ~~~ 5. Run the upgrade script again to apply migrations for v4.4.0: ~~~bash ./upgrade.sh ~~~ ### Expected Behavior The upgrade should complete successfully. All migrations should apply without errors and NetBox should start normally on v4.4.0. ### Observed Behavior The migration fails while applying `users.0005_alter_user_table` with an error indicating that `core_objecttype` does not exist: ~~~bash Applying users.0005_alter_user_table...Traceback (most recent call last): File "/opt/netbox/venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 105, in _execute return self.cursor.execute(sql, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/netbox-/venv/lib/python3.10/site-packages/psycopg/cursor.py", line 97, in execute raise ex.with_traceback(None) psycopg.errors.UndefinedTable: relation "core_objecttype" does not exist LINE 1: ...type"."public", "core_objecttype"."features" FROM "core_obje... ^ ~~~ After this exception, the upgrade process aborts.
adam added the type: bugstatus: acceptedseverity: lowtopic: migrations labels 2025-12-29 21:47:11 +01:00
adam closed this issue 2025-12-29 21:47:11 +01:00
Author
Owner

@pheus commented on GitHub (Sep 7, 2025):

Cross‑reference: This issue was originally raised in GitHub Discussions:
Errors while upgrading from 3.7.8 to 4.4.0 (#20284)


I was able to fix the migration failure by adjusting the dependency ordering for users.0005_alter_user_table so that the core_objecttype table exists before this migration runs.

users.0005_alter_user_table implicitly relies on core_objecttype, but its dependencies didn’t guarantee that core.0018_concrete_objecttype (and the later Extras changes) had been applied first. This led to the error.

c9f823167c/netbox/users/migrations/0005_alter_user_table.py (L26-L29)

I changed the migration’s dependencies as follows:

 class Migration(migrations.Migration):
     dependencies = [
+        ('core', '0018_concrete_objecttype'),
+        ('extras', '0117_move_objectchange'),
         ('users', '0002_squashed_0004'),
-        ('extras', '0113_customfield_rename_object_type'),
     ]

After this change, ./upgrade.sh (or python manage.py migrate) completes without errors and the upgrade to v4.4.0 succeeds for me.

I’m happy to open a PR with this change if the approach looks acceptable.

Thanks for taking a look!

@pheus commented on GitHub (Sep 7, 2025): **Cross‑reference:** This issue was originally raised in GitHub Discussions: Errors while upgrading from 3.7.8 to 4.4.0 (#20284) --- I was able to fix the migration failure by adjusting the dependency ordering for `users.0005_alter_user_table` so that the `core_objecttype` table exists before this migration runs. `users.0005_alter_user_table` implicitly relies on `core_objecttype`, but its dependencies didn’t guarantee that `core.0018_concrete_objecttype` (and the later Extras changes) had been applied first. This led to the error. https://github.com/netbox-community/netbox/blob/c9f823167c3d7b1623459e0acc3902f3eab74ca8/netbox/users/migrations/0005_alter_user_table.py#L26-L29 I changed the migration’s dependencies as follows: ```diff class Migration(migrations.Migration): dependencies = [ + ('core', '0018_concrete_objecttype'), + ('extras', '0117_move_objectchange'), ('users', '0002_squashed_0004'), - ('extras', '0113_customfield_rename_object_type'), ] ``` After this change, `./upgrade.sh` (or `python manage.py migrate`) completes without errors and the upgrade to v4.4.0 succeeds for me. I’m happy to open a PR with this change if the approach looks acceptable. Thanks for taking a look!
Author
Owner

@AnythingOverIP commented on GitHub (Sep 8, 2025):

I was also getting the error on users.0005_alter_user_table while trying to migrate from 3.7.6 to 4.4.0. After applying the above mentioned change, I got past the error I had but now getting the following error on extras.0115_convert_dashboard_widgets:

Applying database migrations (python3 netbox/manage.py migrate)...
Operations to perform:
  Apply all migrations: account, auth, circuits, contenttypes, core, dcim, django_rq, extras, ipam, sessions, social_django, taggit, tenancy, thumbnail, users, virtualization, vpn, wireless
Running migrations:
  Applying extras.0115_convert_dashboard_widgets...Traceback (most recent call last):
  File "/opt/netbox-4.4.0/venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/netbox-4.4.0/venv/lib/python3.12/site-packages/psycopg/cursor.py", line 97, in execute
    raise ex.with_traceback(None)
psycopg.errors.UndefinedTable: relation "core_objecttype" does not exist
LINE 1: ...type"."public", "core_objecttype"."features" FROM "core_obje...
                                                             ^
@AnythingOverIP commented on GitHub (Sep 8, 2025): I was also getting the error on `users.0005_alter_user_table` while trying to migrate from 3.7.6 to 4.4.0. After applying the above mentioned change, I got past the error I had but now getting the following error on `extras.0115_convert_dashboard_widgets`: ``` Applying database migrations (python3 netbox/manage.py migrate)... Operations to perform: Apply all migrations: account, auth, circuits, contenttypes, core, dcim, django_rq, extras, ipam, sessions, social_django, taggit, tenancy, thumbnail, users, virtualization, vpn, wireless Running migrations: Applying extras.0115_convert_dashboard_widgets...Traceback (most recent call last): File "/opt/netbox-4.4.0/venv/lib/python3.12/site-packages/django/db/backends/utils.py", line 105, in _execute return self.cursor.execute(sql, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/netbox-4.4.0/venv/lib/python3.12/site-packages/psycopg/cursor.py", line 97, in execute raise ex.with_traceback(None) psycopg.errors.UndefinedTable: relation "core_objecttype" does not exist LINE 1: ...type"."public", "core_objecttype"."features" FROM "core_obje... ^ ```
Author
Owner

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

I have confirmed that this error occurs only when upgrading directly from v3.7.x to v4.4.0 (which, to be fair, is meant to be supported). As a workaround, you can first upgrade to v4.3.7, and then to v4.4.0 or later:

Migrating from v3.7.8 to v4.3.7:
Running migrations:
  Applying extras.0108_convert_reports_to_scripts... OK
  Applying extras.0109_script_model... OK
  Applying extras.0110_remove_eventrule_action_parameters... OK
  Applying extras.0111_rename_content_types... OK
  Applying extras.0112_tag_update_object_types... OK
  Applying extras.0113_customfield_rename_object_type... OK
  Applying users.0005_alter_user_table... OK
  Applying users.0006_custom_group_model... OK
  Applying users.0007_objectpermission_update_object_types... OK
  Applying users.0008_flip_objectpermission_assignments... OK
  Applying users.0009_update_group_perms... OK
  Applying extras.0114_customfield_add_comments... OK
  Applying extras.0115_convert_dashboard_widgets... OK
  Applying extras.0116_custom_link_button_color... OK
  Applying core.0011_move_objectchange... OK
  Applying extras.0117_move_objectchange... OK
  Applying extras.0118_customfield_uniqueness... OK
  Applying extras.0119_notifications... OK
  Applying extras.0120_eventrule_event_types... OK
  Applying extras.0121_customfield_related_object_filter... OK
  Applying extras.0122_charfield_null_choices... OK
  Applying tenancy.0015_contactassignment_rename_content_type... OK
  Applying tenancy.0016_charfield_null_choices... OK
  Applying ipam.0070_vlangroup_vlan_id_ranges... OK
  Applying ipam.0071_prefix_scope... OK
  Applying dcim.0186_location_facility... OK
  Applying dcim.0187_alter_device_vc_position... OK
  Applying dcim.0188_racktype... OK
  Applying dcim.0189_moduletype_rack_airflow... OK
  Applying dcim.0190_nested_modules... OK
  Applying dcim.0191_module_bay_rebuild... OK
  Applying dcim.0192_inventoryitem_status... OK
  Applying dcim.0193_poweroutlet_color... OK
  Applying ipam.0072_prefix_cached_relations... OK
  Applying ipam.0073_charfield_null_choices... OK
  Applying ipam.0074_vlantranslationpolicy_vlantranslationrule... OK
  Applying ipam.0075_vlan_qinq... OK
  Applying dcim.0194_charfield_null_choices... OK
  Applying dcim.0195_interface_vlan_translation_policy... OK
  Applying dcim.0196_qinq_svlan... OK
  Applying dcim.0197_natural_sort_collation... OK
  Applying circuits.0044_circuit_groups... OK
  Applying circuits.0045_circuit_distance... OK
  Applying circuits.0046_charfield_null_choices... OK
  Applying circuits.0047_circuittermination__termination... OK
  Applying circuits.0048_circuitterminations_cached_relations... OK
  Applying circuits.0049_natural_ordering... OK
  Applying circuits.0050_virtual_circuits... OK
  Applying circuits.0051_virtualcircuit_group_assignment... OK
  Applying circuits.0052_extend_circuit_abs_distance_upper_limit... OK
  Applying core.0012_job_object_type_optional... OK
  Applying core.0013_job_data_encoder... OK
  Applying core.0014_datasource_sync_interval... OK
  Applying core.0015_remove_redundant_indexes... OK
  Applying extras.0123_journalentry_kind_default... OK
  Applying extras.0124_remove_staging... OK
  Applying extras.0125_alter_tag_options_tag_weight... OK
  Applying extras.0126_exporttemplate_file_name... OK
  Applying extras.0127_configtemplate_as_attachment_and_more... OK
  Applying extras.0128_tableconfig... OK
  Applying extras.0129_fix_script_paths... OK
  Applying dcim.0198_natural_ordering... OK
  Applying dcim.0199_macaddress... OK
  Applying dcim.0200_populate_mac_addresses... OK
  Applying dcim.0201_add_power_outlet_status... OK
  Applying dcim.0202_location_comments_region_comments_sitegroup_comments... OK
  Applying dcim.0203_add_rack_outer_height... OK
  Applying dcim.0203_device_role_nested... OK
  Applying dcim.0204_device_role_rebuild... OK
  Applying dcim.0205_moduletypeprofile... OK
  Applying dcim.0206_load_module_type_profiles... OK
  Applying dcim.0207_remove_redundant_indexes... OK
  Applying dcim.0208_devicerole_uniqueness... OK
  Applying dcim.0209_device_component_denorm_site_location... OK
  Applying dcim.0210_macaddress_ordering... OK
  Applying tenancy.0017_natural_ordering... OK
  Applying tenancy.0018_contact_groups... OK
  Applying tenancy.0019_contactgroup_comments_tenantgroup_comments... OK
  Applying tenancy.0020_remove_contactgroupmembership... OK
  Applying virtualization.0039_virtualmachine_serial_number... OK
  Applying virtualization.0040_convert_disk_size... OK
  Applying virtualization.0041_charfield_null_choices... OK
  Applying virtualization.0042_vminterface_vlan_translation_policy... OK
  Applying virtualization.0043_qinq_svlan... OK
  Applying virtualization.0044_cluster_scope... OK
  Applying virtualization.0045_clusters_cached_relations... OK
  Applying virtualization.0046_alter_cluster__location_alter_cluster__region_and_more... OK
  Applying virtualization.0047_natural_ordering... OK
  Applying virtualization.0048_populate_mac_addresses... OK
  Applying ipam.0076_natural_ordering... OK
  Applying ipam.0077_vlangroup_tenant... OK
  Applying ipam.0078_iprange_mark_utilized... OK
  Applying ipam.0079_add_service_fhrp_group_parent_gfk... OK
  Applying ipam.0080_populate_service_parent... OK
  Applying ipam.0081_remove_service_device_virtual_machine_add_parent_gfk_index... OK
  Applying ipam.0082_add_prefix_network_containment_indexes... OK
  Applying social_django.0016_alter_usersocialauth_extra_data... OK
  Applying social_django.0017_usersocialauth_user_social_auth_uid_required... OK
  Applying users.0010_add_token_meta_ordering... OK
  Applying vpn.0005_rename_indexes... OK
  Applying vpn.0006_charfield_null_choices... OK
  Applying vpn.0007_natural_ordering... OK
  Applying vpn.0008_add_l2vpn_status... OK
  Applying vpn.0009_remove_redundant_indexes... OK
  Applying wireless.0009_wirelesslink_distance... OK
  Applying wireless.0010_charfield_null_choices... OK
  Applying wireless.0011_wirelesslan__location_wirelesslan__region_and_more... OK
  Applying wireless.0012_alter_wirelesslan__location_and_more... OK
  Applying wireless.0013_natural_ordering... OK
  Applying wireless.0014_wirelesslangroup_comments... OK
  Applying wireless.0015_extend_wireless_link_abs_distance_upper_limit... OK
Migrating from v4.3.7 to v4.4.0:
Running migrations:
  Applying core.0016_job_log_entries... OK
  Applying core.0017_objectchange_message... OK
  Applying core.0018_concrete_objecttype... OK
  Applying dcim.0211_platform_manufacturer_uniqueness... OK
  Applying dcim.0212_interface_tx_power_negative... OK
  Applying dcim.0213_platform_parent... OK
  Applying dcim.0214_platform_rebuild... OK
  Applying dcim.0215_rackreservation_status... OK
  Applying extras.0130_imageattachment_description... OK
  Applying extras.0131_concrete_objecttype... OK
  Applying extras.0132_configcontextprofile... OK
  Applying thumbnail.0001_initial... OK
  Applying users.0011_concrete_objecttype... OK
@jeremystretch commented on GitHub (Sep 10, 2025): I have confirmed that this error occurs only when upgrading directly from v3.7.x to v4.4.0 (which, to be fair, _is_ meant to be supported). As a workaround, you can first upgrade to v4.3.7, and then to v4.4.0 or later: <details> <summary>Migrating from v3.7.8 to v4.3.7:</summary> ``` Running migrations: Applying extras.0108_convert_reports_to_scripts... OK Applying extras.0109_script_model... OK Applying extras.0110_remove_eventrule_action_parameters... OK Applying extras.0111_rename_content_types... OK Applying extras.0112_tag_update_object_types... OK Applying extras.0113_customfield_rename_object_type... OK Applying users.0005_alter_user_table... OK Applying users.0006_custom_group_model... OK Applying users.0007_objectpermission_update_object_types... OK Applying users.0008_flip_objectpermission_assignments... OK Applying users.0009_update_group_perms... OK Applying extras.0114_customfield_add_comments... OK Applying extras.0115_convert_dashboard_widgets... OK Applying extras.0116_custom_link_button_color... OK Applying core.0011_move_objectchange... OK Applying extras.0117_move_objectchange... OK Applying extras.0118_customfield_uniqueness... OK Applying extras.0119_notifications... OK Applying extras.0120_eventrule_event_types... OK Applying extras.0121_customfield_related_object_filter... OK Applying extras.0122_charfield_null_choices... OK Applying tenancy.0015_contactassignment_rename_content_type... OK Applying tenancy.0016_charfield_null_choices... OK Applying ipam.0070_vlangroup_vlan_id_ranges... OK Applying ipam.0071_prefix_scope... OK Applying dcim.0186_location_facility... OK Applying dcim.0187_alter_device_vc_position... OK Applying dcim.0188_racktype... OK Applying dcim.0189_moduletype_rack_airflow... OK Applying dcim.0190_nested_modules... OK Applying dcim.0191_module_bay_rebuild... OK Applying dcim.0192_inventoryitem_status... OK Applying dcim.0193_poweroutlet_color... OK Applying ipam.0072_prefix_cached_relations... OK Applying ipam.0073_charfield_null_choices... OK Applying ipam.0074_vlantranslationpolicy_vlantranslationrule... OK Applying ipam.0075_vlan_qinq... OK Applying dcim.0194_charfield_null_choices... OK Applying dcim.0195_interface_vlan_translation_policy... OK Applying dcim.0196_qinq_svlan... OK Applying dcim.0197_natural_sort_collation... OK Applying circuits.0044_circuit_groups... OK Applying circuits.0045_circuit_distance... OK Applying circuits.0046_charfield_null_choices... OK Applying circuits.0047_circuittermination__termination... OK Applying circuits.0048_circuitterminations_cached_relations... OK Applying circuits.0049_natural_ordering... OK Applying circuits.0050_virtual_circuits... OK Applying circuits.0051_virtualcircuit_group_assignment... OK Applying circuits.0052_extend_circuit_abs_distance_upper_limit... OK Applying core.0012_job_object_type_optional... OK Applying core.0013_job_data_encoder... OK Applying core.0014_datasource_sync_interval... OK Applying core.0015_remove_redundant_indexes... OK Applying extras.0123_journalentry_kind_default... OK Applying extras.0124_remove_staging... OK Applying extras.0125_alter_tag_options_tag_weight... OK Applying extras.0126_exporttemplate_file_name... OK Applying extras.0127_configtemplate_as_attachment_and_more... OK Applying extras.0128_tableconfig... OK Applying extras.0129_fix_script_paths... OK Applying dcim.0198_natural_ordering... OK Applying dcim.0199_macaddress... OK Applying dcim.0200_populate_mac_addresses... OK Applying dcim.0201_add_power_outlet_status... OK Applying dcim.0202_location_comments_region_comments_sitegroup_comments... OK Applying dcim.0203_add_rack_outer_height... OK Applying dcim.0203_device_role_nested... OK Applying dcim.0204_device_role_rebuild... OK Applying dcim.0205_moduletypeprofile... OK Applying dcim.0206_load_module_type_profiles... OK Applying dcim.0207_remove_redundant_indexes... OK Applying dcim.0208_devicerole_uniqueness... OK Applying dcim.0209_device_component_denorm_site_location... OK Applying dcim.0210_macaddress_ordering... OK Applying tenancy.0017_natural_ordering... OK Applying tenancy.0018_contact_groups... OK Applying tenancy.0019_contactgroup_comments_tenantgroup_comments... OK Applying tenancy.0020_remove_contactgroupmembership... OK Applying virtualization.0039_virtualmachine_serial_number... OK Applying virtualization.0040_convert_disk_size... OK Applying virtualization.0041_charfield_null_choices... OK Applying virtualization.0042_vminterface_vlan_translation_policy... OK Applying virtualization.0043_qinq_svlan... OK Applying virtualization.0044_cluster_scope... OK Applying virtualization.0045_clusters_cached_relations... OK Applying virtualization.0046_alter_cluster__location_alter_cluster__region_and_more... OK Applying virtualization.0047_natural_ordering... OK Applying virtualization.0048_populate_mac_addresses... OK Applying ipam.0076_natural_ordering... OK Applying ipam.0077_vlangroup_tenant... OK Applying ipam.0078_iprange_mark_utilized... OK Applying ipam.0079_add_service_fhrp_group_parent_gfk... OK Applying ipam.0080_populate_service_parent... OK Applying ipam.0081_remove_service_device_virtual_machine_add_parent_gfk_index... OK Applying ipam.0082_add_prefix_network_containment_indexes... OK Applying social_django.0016_alter_usersocialauth_extra_data... OK Applying social_django.0017_usersocialauth_user_social_auth_uid_required... OK Applying users.0010_add_token_meta_ordering... OK Applying vpn.0005_rename_indexes... OK Applying vpn.0006_charfield_null_choices... OK Applying vpn.0007_natural_ordering... OK Applying vpn.0008_add_l2vpn_status... OK Applying vpn.0009_remove_redundant_indexes... OK Applying wireless.0009_wirelesslink_distance... OK Applying wireless.0010_charfield_null_choices... OK Applying wireless.0011_wirelesslan__location_wirelesslan__region_and_more... OK Applying wireless.0012_alter_wirelesslan__location_and_more... OK Applying wireless.0013_natural_ordering... OK Applying wireless.0014_wirelesslangroup_comments... OK Applying wireless.0015_extend_wireless_link_abs_distance_upper_limit... OK ``` </details> <details> <summary>Migrating from v4.3.7 to v4.4.0:</summary> ``` Running migrations: Applying core.0016_job_log_entries... OK Applying core.0017_objectchange_message... OK Applying core.0018_concrete_objecttype... OK Applying dcim.0211_platform_manufacturer_uniqueness... OK Applying dcim.0212_interface_tx_power_negative... OK Applying dcim.0213_platform_parent... OK Applying dcim.0214_platform_rebuild... OK Applying dcim.0215_rackreservation_status... OK Applying extras.0130_imageattachment_description... OK Applying extras.0131_concrete_objecttype... OK Applying extras.0132_configcontextprofile... OK Applying thumbnail.0001_initial... OK Applying users.0011_concrete_objecttype... OK ``` </details>
Author
Owner

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

Unfortunately, reordering the migration's dependencies presents an issue when upgrading to v4.4 from a more recent release (e.g. 4.3.7). We'll need to figure out a different solution.

@jeremystretch commented on GitHub (Sep 11, 2025): Unfortunately, reordering the migration's dependencies presents an issue when upgrading to v4.4 from a more recent release (e.g. 4.3.7). We'll need to figure out a different solution.
Author
Owner

@pheus commented on GitHub (Sep 11, 2025):

Thanks for the fast turnaround! I’m sorry my earlier suggestion created more friction. I didn’t fully appreciate the knock‑on effects of changing an already‑applied migration. Apologies for the noise.

If it’s helpful, here’s what I’m seeing:

  • Trigger point. In users.0005_alter_user_table, the call to delete the users.user ContentType (ContentType.objects.using(db_alias).filter(app_label='users', model='user').delete()) fires Django’s pre_delete signal. In v4.4.0, the receiver extras.signals.notify_object_changed() now consults netbox.models.features.has_feature(), which queries the new concrete core.ObjectType model. On a direct 3.7.8 → 4.4.0 upgrade, the core_objecttype table doesn’t exist yet, so the migration crashes.
  • Why this didn’t bite in 4.3.x. In v4.3.7, notify_object_changed() used the in‑memory feature registry (and ObjectType was a proxy, not a table), so the same users.0005 migration didn’t need to query core_objecttype and proceeded normally.
  • Takeaway. Editing dependencies on users.0005 isn’t viable (it’s already applied for 4.3.x → 4.4.0 upgrades). We’ll need a forward‑only remedy that preserves history.

Again, apologies for the churn! Thank you for the quick engagement. If I’ve misunderstood anything here, please let me know.

@pheus commented on GitHub (Sep 11, 2025): Thanks for the fast turnaround! I’m sorry my earlier suggestion created more friction. I didn’t fully appreciate the knock‑on effects of changing an already‑applied migration. Apologies for the noise. If it’s helpful, here’s what I’m seeing: - **Trigger point.** In `users.0005_alter_user_table`, the call to delete the `users.user` `ContentType` (`ContentType.objects.using(db_alias).filter(app_label='users', model='user').delete()`) fires Django’s `pre_delete` signal. In **v4.4.0**, the receiver `extras.signals.notify_object_changed()` now consults `netbox.models.features.has_feature()`, which queries the new **concrete** `core.ObjectType` model. On a direct **3.7.8 → 4.4.0** upgrade, the `core_objecttype` table doesn’t exist yet, so the migration crashes. - **Why this didn’t bite in 4.3.x.** In **v4.3.7**, `notify_object_changed()` used the in‑memory feature registry (and `ObjectType` was a proxy, not a table), so the same `users.0005` migration didn’t need to query `core_objecttype` and proceeded normally. - **Takeaway.** Editing dependencies on `users.0005` isn’t viable (it’s already applied for 4.3.x → 4.4.0 upgrades). We’ll need a **forward‑only** remedy that preserves history. Again, apologies for the churn! Thank you for the quick engagement. If I’ve misunderstood anything here, please let me know.
Author
Owner

@jnovinger commented on GitHub (Sep 11, 2025):

Apologies, this got auto-closed because I included some details in the merge message that reverted the earlier fix attempt.

@jnovinger commented on GitHub (Sep 11, 2025): Apologies, this got auto-closed because I included some details in the merge message that reverted the earlier fix attempt.
Author
Owner

@pheus commented on GitHub (Sep 12, 2025):

Thank you to everyone involved — and my sincere apologies for the churn.

I’m not a Django migrations expert, so I may be missing something here. I tried a few forward‑only approaches to keep upgrades possible, and the most promising in my testing was to squash existing migrations and adjust dependencies while keeping the original migrations intact.

For the users app, I was able to get through using the approach below. However, after adding more realistic data, I’m hitting an issue in extras (a RunPython step during the custom dashboard conversion), which suggests we might need additional, carefully targeted squashing on the non‑users side — and that could risk circular dependencies. Given these trade‑offs, I’m starting to think the most pragmatic path might be to document an intermediate upgrade step (e.g., 3.7.8 → 4.3.7 first, then 4.4.0+), rather than allowing a single hop from 3.7.8 straight to 4.4.0.

Apologize again for any noise. If this is not helpful, I’m okay to step back.


For reference (what worked for me in users)

To make the users upgrade path reliable without modifying already‑applied migrations or changing runtime behavior, I prepared a squashed migration in the users app that replaces 0005 through 0011 (as of v4.4.0). This squashed file adds the required cross‑app dependencies and ports the custom RunPython logic so that direct upgrades have the correct ordering and data updates.

What this does

  • Replaces users migrations 00050011 with a single squashed migration.
  • Declares dependencies on extras.0117_move_objectchange and core.0018_concrete_objecttype so that:
    • core_objectchange exists before any operations that touch it.
    • The concrete core.ObjectType table exists before signal handlers or data migrations that query it.
  • Ports the needed RunPython functions to use core.ObjectType where appropriate.

Proposed squashed migration (users)
Suggested filename: netbox/users/migrations/0012_squashed_0005_0011.py

import django.db.migrations.operations.special
import users.models.users
from django.db import migrations, models


def update_content_types(apps, schema_editor):
    ObjectType = apps.get_model('core', 'ObjectType')
    CustomField = apps.get_model('extras', 'CustomField')
    db_alias = schema_editor.connection.alias

    # Delete the new ContentTypes effected by the new models in the users app
    ObjectType.objects.using(db_alias).filter(app_label='users', model='user').delete()

    # Update the app labels of the original ContentTypes for auth.User to ensure
    # that any foreign key references are preserved
    ObjectType.objects.using(db_alias).filter(app_label='auth', model='user').update(app_label='users')

    netboxuser_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='netboxuser').first()
    if netboxuser_ct:
        user_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='user').first()
        CustomField.objects.using(db_alias).filter(related_object_type_id=netboxuser_ct.id).update(
            related_object_type_id=user_ct.id
        )
        netboxuser_ct.delete()


def update_custom_fields(apps, schema_editor):
    """
    Update any CustomFields referencing the old Group model to use the new model.
    """
    ObjectType = apps.get_model('core', 'ObjectType')
    CustomField = apps.get_model('extras', 'CustomField')
    Group = apps.get_model('users', 'Group')
    db_alias = schema_editor.connection.alias

    if old_ct := ObjectType.objects.using(db_alias).filter(app_label='users', model='netboxgroup').first():
        new_ct = ObjectType.objects.get_for_model(Group)
        CustomField.objects.using(db_alias).filter(related_object_type=old_ct).update(related_object_type=new_ct)


def update_group_content_types(apps, schema_editor):
    ObjectType = apps.get_model('core', 'ObjectType')
    ObjectPermission = apps.get_model('users', 'ObjectPermission')
    db_alias = schema_editor.connection.alias

    auth_group_ct = ObjectType.objects.using(db_alias).filter(app_label='auth', model='group').first()
    users_group_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='group').first()
    if auth_group_ct and users_group_ct:
        perms = ObjectPermission.objects.using(db_alias).filter(object_types__in=[auth_group_ct])
        for perm in perms:
            perm.object_types.remove(auth_group_ct)
            perm.object_types.add(users_group_ct)
            perm.save()


class Migration(migrations.Migration):

    replaces = [
        ('users', '0005_alter_user_table'),
        ('users', '0006_custom_group_model'),
        ('users', '0007_objectpermission_update_object_types'),
        ('users', '0008_flip_objectpermission_assignments'),
        ('users', '0009_update_group_perms'),
        ('users', '0010_add_token_meta_ordering'),
        ('users', '0011_concrete_objecttype'),
    ]

    dependencies = [
        ('contenttypes', '0002_remove_content_type_name'),
        ('core', '0010_gfk_indexes'),
        ('core', '0018_concrete_objecttype'),
        ('extras', '0117_move_objectchange'),
        ('users', '0002_squashed_0004'),
    ]

    operations = [
        migrations.AlterModelTable(
            name='user',
            table=None,
        ),
        migrations.RunSQL(
            sql='ALTER TABLE users_user ALTER COLUMN id TYPE bigint',
        ),
        migrations.RunSQL(
            sql='ALTER TABLE auth_user_groups_id_seq RENAME TO users_user_groups_id_seq',
        ),
        migrations.RunSQL(
            sql='ALTER TABLE auth_user_id_seq RENAME TO users_user_id_seq',
        ),
        migrations.RunSQL(
            sql='ALTER TABLE auth_user_user_permissions_id_seq RENAME TO users_user_user_permissions_id_seq',
        ),
        migrations.RunSQL(
            sql='ALTER INDEX auth_user_pkey RENAME TO users_user_pkey',
        ),
        migrations.RunSQL(
            sql='ALTER INDEX auth_user_username_6821ab7c_like RENAME TO users_user_username_06e46fe6_like',
        ),
        migrations.RunSQL(
            sql='ALTER INDEX auth_user_username_key RENAME TO users_user_username_key',
        ),
        migrations.RunPython(
            code=update_content_types,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.CreateModel(
            name='Group',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
                ('name', models.CharField(max_length=150, unique=True)),
                ('description', models.CharField(blank=True, max_length=200)),
                ('permissions', models.ManyToManyField(blank=True, related_name='groups', related_query_name='group', to='auth.permission')),
            ],
            options={
                'ordering': ('name',),
                'verbose_name': 'group',
                'verbose_name_plural': 'groups',
            },
            managers=[
                ('objects', users.models.users.GroupManager()),
            ],
        ),
        migrations.RunSQL(
            sql="INSERT INTO users_group (SELECT id, name, '' AS description FROM auth_group)",
        ),
        migrations.RunSQL(
            sql="SELECT setval('users_group_id_seq', (SELECT MAX(id) FROM users_group))",
        ),
        migrations.AlterField(
            model_name='user',
            name='groups',
            field=models.ManyToManyField(blank=True, related_name='users', related_query_name='user', to='users.group'),
        ),
        migrations.AlterField(
            model_name='objectpermission',
            name='groups',
            field=models.ManyToManyField(blank=True, related_name='object_permissions', to='users.group'),
        ),
        migrations.RunSQL(
            sql='DELETE from auth_group_permissions',
        ),
        migrations.RunSQL(
            sql='DELETE from auth_group',
        ),
        migrations.RunPython(
            code=update_custom_fields,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.DeleteModel(
            name='NetBoxGroup',
        ),
        migrations.AlterField(
            model_name='objectpermission',
            name='object_types',
            field=models.ManyToManyField(related_name='object_permissions', to='core.objecttype'),
        ),
        migrations.SeparateDatabaseAndState(
            database_operations=[
                migrations.RunSQL(
                    sql='ALTER TABLE users_objectpermission_groups  RENAME TO users_group_object_permissions',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_objectpermission_groups_id_seq  RENAME TO users_group_object_permissions_id_seq',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_group_object_permissions RENAME CONSTRAINT users_objectpermissi_group_id_fb7ba6e0_fk_users_gro TO users_group_object_p_group_id_90dd183a_fk_users_gro',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_group_object_permissions DROP CONSTRAINT IF EXISTS users_objectpermissi_objectpermission_id_2f7cc117_fk_users_obj',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_group_object_permissions ADD CONSTRAINT users_group_object_p_objectpermission_id_dd489dc4_fk_users_obj FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) DEFERRABLE INITIALLY DEFERRED',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_groups_pkey   RENAME TO users_group_object_permissions_pkey',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_g_objectpermission_id_grou_3b62a39c_uniq   RENAME TO users_group_object_permi_group_id_objectpermissio_db1f8cbe_uniq',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_groups_group_id_fb7ba6e0  RENAME TO users_group_object_permissions_group_id_90dd183a',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_groups_objectpermission_id_2f7cc117  RENAME TO users_group_object_permissions_objectpermission_id_dd489dc4',
                ),
            ],
            state_operations=[
                migrations.RemoveField(
                    model_name='objectpermission',
                    name='groups',
                ),
                migrations.AddField(
                    model_name='group',
                    name='object_permissions',
                    field=models.ManyToManyField(blank=True, related_name='groups', to='users.objectpermission'),
                ),
            ],
        ),
        migrations.SeparateDatabaseAndState(
            database_operations=[
                migrations.RunSQL(
                    sql='ALTER TABLE users_objectpermission_users  RENAME TO users_user_object_permissions',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_objectpermission_users_id_seq  RENAME TO users_user_object_permissions_id_seq',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_user_object_permissions RENAME CONSTRAINT users_objectpermission_users_user_id_16c0905d_fk_auth_user_id TO users_user_object_permissions_user_id_9d647aac_fk_users_user_id',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_user_object_permissions DROP CONSTRAINT IF EXISTS users_objectpermissi_objectpermission_id_78a9c2e6_fk_users_obj',
                ),
                migrations.RunSQL(
                    sql='ALTER TABLE users_user_object_permissions ADD CONSTRAINT users_user_object_pe_objectpermission_id_29b431b4_fk_users_obj FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) DEFERRABLE INITIALLY DEFERRED',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_users_pkey   RENAME TO users_user_object_permissions_pkey',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_u_objectpermission_id_user_3a7db108_uniq   RENAME TO users_user_object_permis_user_id_objectpermission_0a98550e_uniq',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_users_user_id_16c0905d  RENAME TO users_user_object_permissions_user_id_9d647aac',
                ),
                migrations.RunSQL(
                    sql='ALTER INDEX users_objectpermission_users_objectpermission_id_78a9c2e6  RENAME TO users_user_object_permissions_objectpermission_id_29b431b4',
                ),
            ],
            state_operations=[
                migrations.RemoveField(
                    model_name='objectpermission',
                    name='users',
                ),
                migrations.AddField(
                    model_name='user',
                    name='object_permissions',
                    field=models.ManyToManyField(blank=True, related_name='users', to='users.objectpermission'),
                ),
            ],
        ),
        migrations.RunPython(
            code=update_group_content_types,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.AlterModelOptions(
            name='token',
            options={'ordering': ('-created',)},
        ),
        migrations.AlterField(
            model_name='objectpermission',
            name='object_types',
            field=models.ManyToManyField(related_name='object_permissions', to='contenttypes.contenttype'),
        ),
    ]

Once again, thank you for the guidance and patience. Apologies if I’ve caused extra work here.

@pheus commented on GitHub (Sep 12, 2025): **Thank you to everyone involved — and my sincere apologies for the churn.** I’m not a Django migrations expert, so I may be missing something here. I tried a few forward‑only approaches to keep upgrades possible, and the most promising in my testing was to **squash** existing migrations and adjust dependencies while keeping the original migrations intact. For the **`users`** app, I was able to get through using the approach below. However, after adding more realistic data, I’m hitting an issue in **`extras`** (a `RunPython` step during the custom dashboard conversion), which suggests we might need additional, carefully targeted squashing on the non‑users side — and that could risk circular dependencies. Given these trade‑offs, I’m starting to think the most pragmatic path might be to **document an intermediate upgrade step** (e.g., 3.7.8 → 4.3.7 first, then 4.4.0+), rather than allowing a single hop from 3.7.8 straight to 4.4.0. Apologize again for any noise. If this is not helpful, I’m okay to step back. --- ### For reference (what worked for me in `users`) To make the `users` upgrade path reliable **without** modifying already‑applied migrations or changing runtime behavior, I prepared a **squashed migration** in the **users** app that replaces `0005` through `0011` (as of v4.4.0). This squashed file adds the required cross‑app dependencies and ports the custom `RunPython` logic so that direct upgrades have the correct ordering and data updates. **What this does** - **Replaces** users migrations `0005` → `0011` with a single squashed migration. - **Declares dependencies** on `extras.0117_move_objectchange` and `core.0018_concrete_objecttype` so that: - `core_objectchange` exists before any operations that touch it. - The **concrete** `core.ObjectType` table exists before signal handlers or data migrations that query it. - **Ports** the needed `RunPython` functions to use `core.ObjectType` where appropriate. **Proposed squashed migration (users)** _Suggested filename: `netbox/users/migrations/0012_squashed_0005_0011.py`_ ```python import django.db.migrations.operations.special import users.models.users from django.db import migrations, models def update_content_types(apps, schema_editor): ObjectType = apps.get_model('core', 'ObjectType') CustomField = apps.get_model('extras', 'CustomField') db_alias = schema_editor.connection.alias # Delete the new ContentTypes effected by the new models in the users app ObjectType.objects.using(db_alias).filter(app_label='users', model='user').delete() # Update the app labels of the original ContentTypes for auth.User to ensure # that any foreign key references are preserved ObjectType.objects.using(db_alias).filter(app_label='auth', model='user').update(app_label='users') netboxuser_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='netboxuser').first() if netboxuser_ct: user_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='user').first() CustomField.objects.using(db_alias).filter(related_object_type_id=netboxuser_ct.id).update( related_object_type_id=user_ct.id ) netboxuser_ct.delete() def update_custom_fields(apps, schema_editor): """ Update any CustomFields referencing the old Group model to use the new model. """ ObjectType = apps.get_model('core', 'ObjectType') CustomField = apps.get_model('extras', 'CustomField') Group = apps.get_model('users', 'Group') db_alias = schema_editor.connection.alias if old_ct := ObjectType.objects.using(db_alias).filter(app_label='users', model='netboxgroup').first(): new_ct = ObjectType.objects.get_for_model(Group) CustomField.objects.using(db_alias).filter(related_object_type=old_ct).update(related_object_type=new_ct) def update_group_content_types(apps, schema_editor): ObjectType = apps.get_model('core', 'ObjectType') ObjectPermission = apps.get_model('users', 'ObjectPermission') db_alias = schema_editor.connection.alias auth_group_ct = ObjectType.objects.using(db_alias).filter(app_label='auth', model='group').first() users_group_ct = ObjectType.objects.using(db_alias).filter(app_label='users', model='group').first() if auth_group_ct and users_group_ct: perms = ObjectPermission.objects.using(db_alias).filter(object_types__in=[auth_group_ct]) for perm in perms: perm.object_types.remove(auth_group_ct) perm.object_types.add(users_group_ct) perm.save() class Migration(migrations.Migration): replaces = [ ('users', '0005_alter_user_table'), ('users', '0006_custom_group_model'), ('users', '0007_objectpermission_update_object_types'), ('users', '0008_flip_objectpermission_assignments'), ('users', '0009_update_group_perms'), ('users', '0010_add_token_meta_ordering'), ('users', '0011_concrete_objecttype'), ] dependencies = [ ('contenttypes', '0002_remove_content_type_name'), ('core', '0010_gfk_indexes'), ('core', '0018_concrete_objecttype'), ('extras', '0117_move_objectchange'), ('users', '0002_squashed_0004'), ] operations = [ migrations.AlterModelTable( name='user', table=None, ), migrations.RunSQL( sql='ALTER TABLE users_user ALTER COLUMN id TYPE bigint', ), migrations.RunSQL( sql='ALTER TABLE auth_user_groups_id_seq RENAME TO users_user_groups_id_seq', ), migrations.RunSQL( sql='ALTER TABLE auth_user_id_seq RENAME TO users_user_id_seq', ), migrations.RunSQL( sql='ALTER TABLE auth_user_user_permissions_id_seq RENAME TO users_user_user_permissions_id_seq', ), migrations.RunSQL( sql='ALTER INDEX auth_user_pkey RENAME TO users_user_pkey', ), migrations.RunSQL( sql='ALTER INDEX auth_user_username_6821ab7c_like RENAME TO users_user_username_06e46fe6_like', ), migrations.RunSQL( sql='ALTER INDEX auth_user_username_key RENAME TO users_user_username_key', ), migrations.RunPython( code=update_content_types, reverse_code=django.db.migrations.operations.special.RunPython.noop, ), migrations.CreateModel( name='Group', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('name', models.CharField(max_length=150, unique=True)), ('description', models.CharField(blank=True, max_length=200)), ('permissions', models.ManyToManyField(blank=True, related_name='groups', related_query_name='group', to='auth.permission')), ], options={ 'ordering': ('name',), 'verbose_name': 'group', 'verbose_name_plural': 'groups', }, managers=[ ('objects', users.models.users.GroupManager()), ], ), migrations.RunSQL( sql="INSERT INTO users_group (SELECT id, name, '' AS description FROM auth_group)", ), migrations.RunSQL( sql="SELECT setval('users_group_id_seq', (SELECT MAX(id) FROM users_group))", ), migrations.AlterField( model_name='user', name='groups', field=models.ManyToManyField(blank=True, related_name='users', related_query_name='user', to='users.group'), ), migrations.AlterField( model_name='objectpermission', name='groups', field=models.ManyToManyField(blank=True, related_name='object_permissions', to='users.group'), ), migrations.RunSQL( sql='DELETE from auth_group_permissions', ), migrations.RunSQL( sql='DELETE from auth_group', ), migrations.RunPython( code=update_custom_fields, reverse_code=django.db.migrations.operations.special.RunPython.noop, ), migrations.DeleteModel( name='NetBoxGroup', ), migrations.AlterField( model_name='objectpermission', name='object_types', field=models.ManyToManyField(related_name='object_permissions', to='core.objecttype'), ), migrations.SeparateDatabaseAndState( database_operations=[ migrations.RunSQL( sql='ALTER TABLE users_objectpermission_groups RENAME TO users_group_object_permissions', ), migrations.RunSQL( sql='ALTER TABLE users_objectpermission_groups_id_seq RENAME TO users_group_object_permissions_id_seq', ), migrations.RunSQL( sql='ALTER TABLE users_group_object_permissions RENAME CONSTRAINT users_objectpermissi_group_id_fb7ba6e0_fk_users_gro TO users_group_object_p_group_id_90dd183a_fk_users_gro', ), migrations.RunSQL( sql='ALTER TABLE users_group_object_permissions DROP CONSTRAINT IF EXISTS users_objectpermissi_objectpermission_id_2f7cc117_fk_users_obj', ), migrations.RunSQL( sql='ALTER TABLE users_group_object_permissions ADD CONSTRAINT users_group_object_p_objectpermission_id_dd489dc4_fk_users_obj FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) DEFERRABLE INITIALLY DEFERRED', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_groups_pkey RENAME TO users_group_object_permissions_pkey', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_g_objectpermission_id_grou_3b62a39c_uniq RENAME TO users_group_object_permi_group_id_objectpermissio_db1f8cbe_uniq', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_groups_group_id_fb7ba6e0 RENAME TO users_group_object_permissions_group_id_90dd183a', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_groups_objectpermission_id_2f7cc117 RENAME TO users_group_object_permissions_objectpermission_id_dd489dc4', ), ], state_operations=[ migrations.RemoveField( model_name='objectpermission', name='groups', ), migrations.AddField( model_name='group', name='object_permissions', field=models.ManyToManyField(blank=True, related_name='groups', to='users.objectpermission'), ), ], ), migrations.SeparateDatabaseAndState( database_operations=[ migrations.RunSQL( sql='ALTER TABLE users_objectpermission_users RENAME TO users_user_object_permissions', ), migrations.RunSQL( sql='ALTER TABLE users_objectpermission_users_id_seq RENAME TO users_user_object_permissions_id_seq', ), migrations.RunSQL( sql='ALTER TABLE users_user_object_permissions RENAME CONSTRAINT users_objectpermission_users_user_id_16c0905d_fk_auth_user_id TO users_user_object_permissions_user_id_9d647aac_fk_users_user_id', ), migrations.RunSQL( sql='ALTER TABLE users_user_object_permissions DROP CONSTRAINT IF EXISTS users_objectpermissi_objectpermission_id_78a9c2e6_fk_users_obj', ), migrations.RunSQL( sql='ALTER TABLE users_user_object_permissions ADD CONSTRAINT users_user_object_pe_objectpermission_id_29b431b4_fk_users_obj FOREIGN KEY (objectpermission_id) REFERENCES users_objectpermission(id) DEFERRABLE INITIALLY DEFERRED', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_users_pkey RENAME TO users_user_object_permissions_pkey', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_u_objectpermission_id_user_3a7db108_uniq RENAME TO users_user_object_permis_user_id_objectpermission_0a98550e_uniq', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_users_user_id_16c0905d RENAME TO users_user_object_permissions_user_id_9d647aac', ), migrations.RunSQL( sql='ALTER INDEX users_objectpermission_users_objectpermission_id_78a9c2e6 RENAME TO users_user_object_permissions_objectpermission_id_29b431b4', ), ], state_operations=[ migrations.RemoveField( model_name='objectpermission', name='users', ), migrations.AddField( model_name='user', name='object_permissions', field=models.ManyToManyField(blank=True, related_name='users', to='users.objectpermission'), ), ], ), migrations.RunPython( code=update_group_content_types, reverse_code=django.db.migrations.operations.special.RunPython.noop, ), migrations.AlterModelOptions( name='token', options={'ordering': ('-created',)}, ), migrations.AlterField( model_name='objectpermission', name='object_types', field=models.ManyToManyField(related_name='object_permissions', to='contenttypes.contenttype'), ), ] ``` Once again, thank you for the guidance and patience. Apologies if I’ve caused extra work here.
Author
Owner

@derekchisholm commented on GitHub (Sep 17, 2025):

I'm facing a similar issue upgrading from 4.0.5 to 4.1.1 using releases.

Applying extras.0117_move_objectchange...Traceback (most recent call last):
  File "/opt/netbox-4.4.1/venv/lib64/python3.11/site-packages/django/db/backends/utils.py", line 105, in _execute
    return self.cursor.execute(sql, params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/netbox-4.4.1/venv/lib64/python3.11/site-packages/psycopg/cursor.py", line 97, in execute
    raise ex.with_traceback(None)
psycopg.errors.UndefinedTable: relation "core_objecttype" does not exist
LINE 1: ...type"."public", "core_objecttype"."features" FROM "core_obje...

I'm happy to help with additional info or open a new issue if needed.

@derekchisholm commented on GitHub (Sep 17, 2025): I'm facing a similar issue upgrading from 4.0.5 to 4.1.1 using releases. ``` Applying extras.0117_move_objectchange...Traceback (most recent call last): File "/opt/netbox-4.4.1/venv/lib64/python3.11/site-packages/django/db/backends/utils.py", line 105, in _execute return self.cursor.execute(sql, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/opt/netbox-4.4.1/venv/lib64/python3.11/site-packages/psycopg/cursor.py", line 97, in execute raise ex.with_traceback(None) psycopg.errors.UndefinedTable: relation "core_objecttype" does not exist LINE 1: ...type"."public", "core_objecttype"."features" FROM "core_obje... ``` I'm happy to help with additional info or open a new issue if needed.
Author
Owner

@timfischbach commented on GitHub (Oct 1, 2025):

Modifying the DB with the following command by another user fixed the issue for me:

It seems the failing migration extras.0117_move_objectchange fails, if core.0011_move_objectchange is not executed in the same run.

Try

delete from django_migrations WHERE name='0011_move_objectchange';

The 0011_move_objectchange is a state only migration that does not change anything in the database. On the first run there was a permission problem on the database, which caused extras.0117_move_objectchange to fail, but core.0011_move_objectchange was executed and recorded in the migrations table, because it does not change the database structure.

More infos about this here:
https://github.com/netbox-community/netbox/discussions/17388#discussioncomment-10582898

@timfischbach commented on GitHub (Oct 1, 2025): Modifying the DB with the following command by another user fixed the issue for me: > It seems the failing migration extras.0117_move_objectchange fails, if core.0011_move_objectchange is not executed in the same run. > > Try > > ``` > delete from django_migrations WHERE name='0011_move_objectchange'; > ``` > > The 0011_move_objectchange is a state only migration that does not change anything in the database. On the first run there was a permission problem on the database, which caused extras.0117_move_objectchange to fail, but core.0011_move_objectchange was executed and recorded in the migrations table, because it does not change the database structure. More infos about this here: https://github.com/netbox-community/netbox/discussions/17388#discussioncomment-10582898
Author
Owner

@jeremystretch commented on GitHub (Oct 6, 2025):

I've just submitted an alternative PR (#20518) which solves this from a different angle, though ultimately still hinges on checking for the presence of the core_objecttype table when calling ObjectType.objects.get_for_model().

@jeremystretch commented on GitHub (Oct 6, 2025): I've just submitted an alternative PR (#20518) which solves this from a different angle, though ultimately still hinges on checking for the presence of the `core_objecttype` table when calling `ObjectType.objects.get_for_model()`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11586