ipam.0070_vlangroup_vlan_id_ranges fails during upgrade to v4.5.1: search indexer tries to read missing VLANGroup.comments #404

Closed
opened 2026-04-05 16:29:54 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @avagner95 on 2/6/2026

NetBox Edition

NetBox Community

NetBox Version

v4.5.1

Python Version

3.12

Steps to Reproduce

Description

Migration ipam/migrations/0070_vlangroup_vlan_id_ranges.py fails on databases that already contain VLANGroup rows (vlans_vlangroup not empty).

The migration calls group.save() inside set_vid_ranges(). This triggers post_save, which runs the search backend caching handler. During caching, the search indexer attempts to access comments on a VLANGroup instance, but VLANGroup has no comments attribute, resulting in an exception and aborting migrations.

Steps to reproduce
1. Have a NetBox DB with existing VLANGroup records (vlans_vlangroup contains rows).
2. Upgrade NetBox to v4.5.1 (tested from v3.7.7 and v4.3.1).
3. Run migrations (manage.py migrate or start netbox-docker which runs migrations).
4. Migration fails with AttributeError.

Expected behavior

Migrations complete successfully on v4.5.1 with existing VLANGroup data.

Actual behavior

Migration fails with:

netbox-docker-netbox-1         |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/migrations/executor.py", line 255, in apply_migration
netbox-docker-netbox-1         |     state = migration.apply(state, schema_editor)
netbox-docker-netbox-1         |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-docker-netbox-1         |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/migrations/migration.py", line 132, in apply
netbox-docker-netbox-1         |     operation.database_forwards(
netbox-docker-netbox-1         |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/migrations/operations/special.py", line 196, in database_forwards
netbox-docker-netbox-1         |     self.code(from_state.apps, schema_editor)
netbox-docker-netbox-1         |   File "/opt/netbox/netbox/ipam/migrations/0070_vlangroup_vlan_id_ranges.py", line 19, in set_vid_ranges
netbox-docker-netbox-1         |     group.save()
netbox-docker-netbox-1         |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 902, in save
netbox-docker-netbox-1         |     self.save_base(
netbox-docker-netbox-1         |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 1023, in save_base
netbox-docker-netbox-1         |     post_save.send(
netbox-docker-netbox-1         |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/dispatch/dispatcher.py", line 189, in send
netbox-docker-netbox-1         |     response = receiver(signal=self, sender=sender, **named)
netbox-docker-netbox-1         |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-docker-netbox-1         |   File "/opt/netbox/netbox/netbox/search/backends.py", line 65, in caching_handler
netbox-docker-netbox-1         |     self.cache(instance, remove_existing=not created)
netbox-docker-netbox-1         |   File "/opt/netbox/netbox/netbox/search/backends.py", line 220, in cache
netbox-docker-netbox-1         |     for field in indexer.to_cache(instance, custom_fields=custom_fields):
netbox-docker-netbox-1         |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-docker-netbox-1         |   File "/opt/netbox/netbox/netbox/search/__init__.py", line 111, in to_cache
netbox-docker-netbox-1         |     type_ = cls.get_attr_type(instance, name)
netbox-docker-netbox-1         |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-docker-netbox-1         |   File "/opt/netbox/netbox/netbox/search/__init__.py", line 67, in get_attr_type
netbox-docker-netbox-1         |     value = getattr(instance, field_name)
netbox-docker-netbox-1         |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-docker-netbox-1         | AttributeError: 'VLANGroup' object has no attribute 'comments'
netbox-docker-netbox-1 exited with code 1
netbox-docker-postgres-1       | 2026-02-05 12:20:56.830 UTC [31] LOG:  checkpoint starting: time

Notes / suspicion

It looks like the search index definition for VLANGroup (or a generic indexer config) includes comments as a cached field, but the VLANGroup model does not define comments. Because the migration uses .save(), it hits the indexing logic and fails before migrations can finish.

Environment
• Upgrading NetBox (netbox-docker)
• Reproduced upgrading 3.7.7 → 4.5.1 and 4.3.1 → 4.5.1
• Python: 3.12 (as in netbox-docker image)

Expected Behavior

Migrations complete successfully on v4.5.1 with existing VLANGroup data.

Observed Behavior

Migrations complete with erorr on v4.5.1 with existing VLANGroup data.

*Originally created by @avagner95 on 2/6/2026* ### NetBox Edition NetBox Community ### NetBox Version v4.5.1 ### Python Version 3.12 ### Steps to Reproduce Description Migration ipam/migrations/0070_vlangroup_vlan_id_ranges.py fails on databases that already contain VLANGroup rows (vlans_vlangroup not empty). The migration calls group.save() inside set_vid_ranges(). This triggers post_save, which runs the search backend caching handler. During caching, the search indexer attempts to access comments on a VLANGroup instance, but VLANGroup has no comments attribute, resulting in an exception and aborting migrations. Steps to reproduce 1. Have a NetBox DB with existing VLANGroup records (vlans_vlangroup contains rows). 2. Upgrade NetBox to v4.5.1 (tested from v3.7.7 and v4.3.1). 3. Run migrations (manage.py migrate or start netbox-docker which runs migrations). 4. Migration fails with AttributeError. Expected behavior Migrations complete successfully on v4.5.1 with existing VLANGroup data. Actual behavior Migration fails with: ``` netbox-docker-netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/migrations/executor.py", line 255, in apply_migration netbox-docker-netbox-1 | state = migration.apply(state, schema_editor) netbox-docker-netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-docker-netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/migrations/migration.py", line 132, in apply netbox-docker-netbox-1 | operation.database_forwards( netbox-docker-netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/migrations/operations/special.py", line 196, in database_forwards netbox-docker-netbox-1 | self.code(from_state.apps, schema_editor) netbox-docker-netbox-1 | File "/opt/netbox/netbox/ipam/migrations/0070_vlangroup_vlan_id_ranges.py", line 19, in set_vid_ranges netbox-docker-netbox-1 | group.save() netbox-docker-netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 902, in save netbox-docker-netbox-1 | self.save_base( netbox-docker-netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/db/models/base.py", line 1023, in save_base netbox-docker-netbox-1 | post_save.send( netbox-docker-netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/dispatch/dispatcher.py", line 189, in send netbox-docker-netbox-1 | response = receiver(signal=self, sender=sender, **named) netbox-docker-netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-docker-netbox-1 | File "/opt/netbox/netbox/netbox/search/backends.py", line 65, in caching_handler netbox-docker-netbox-1 | self.cache(instance, remove_existing=not created) netbox-docker-netbox-1 | File "/opt/netbox/netbox/netbox/search/backends.py", line 220, in cache netbox-docker-netbox-1 | for field in indexer.to_cache(instance, custom_fields=custom_fields): netbox-docker-netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-docker-netbox-1 | File "/opt/netbox/netbox/netbox/search/__init__.py", line 111, in to_cache netbox-docker-netbox-1 | type_ = cls.get_attr_type(instance, name) netbox-docker-netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-docker-netbox-1 | File "/opt/netbox/netbox/netbox/search/__init__.py", line 67, in get_attr_type netbox-docker-netbox-1 | value = getattr(instance, field_name) netbox-docker-netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-docker-netbox-1 | AttributeError: 'VLANGroup' object has no attribute 'comments' netbox-docker-netbox-1 exited with code 1 netbox-docker-postgres-1 | 2026-02-05 12:20:56.830 UTC [31] LOG: checkpoint starting: time ``` Notes / suspicion It looks like the search index definition for VLANGroup (or a generic indexer config) includes comments as a cached field, but the VLANGroup model does not define comments. Because the migration uses .save(), it hits the indexing logic and fails before migrations can finish. Environment • Upgrading NetBox (netbox-docker) • Reproduced upgrading 3.7.7 → 4.5.1 and 4.3.1 → 4.5.1 • Python: 3.12 (as in netbox-docker image) ### Expected Behavior Migrations complete successfully on v4.5.1 with existing VLANGroup data. ### Observed Behavior Migrations complete with erorr on v4.5.1 with existing VLANGroup data.
MrUnknownDE added the status: acceptedstatus: acceptednetboxstatus: acceptedseverity: lowtype: bugstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptednetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: low labels 2026-04-05 16:30:02 +02:00
Sign in to join this conversation.
No Label netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low severity: low status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/netbox#404