Interface_count does not sync #11723

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

Originally created by @kenneth-sfv on GitHub (Oct 14, 2025).

NetBox Edition

NetBox Community

NetBox Version

v4.4.2

Python Version

3.12

Steps to Reproduce

For VirtualMachine:

  1. In nbshell
# ./manage.py nbshell
from virtualization.models import Cluster, VirtualMachine, VMInterface
cluster = Cluster.objects.get(name="cluster1")
vm = VirtualMachine(name="vm1", cluster=cluster)
vm.full_clean()
vm.save() #Saving vm to be able to add nic below

nic1 = VMInterface(virtual_machine=vm, name="nic1")
nic1.full_clean()
nic1.save()
vm.save() # with this will trigger the bug

2.Check GUI -> Virtual Machines -> Configure Table -> Add Interface Columns -> It shows '0'.
3.Check GUI -> Virtual Machines -> vm1 -> Interfaces tab shows nothing, -> in interface tab, nic1 is created.

For Devices:

  1. in nbshell
# manage.py nbshell
from dcim.models import DeviceRole, DeviceType,Site,Device,Interface
role=DeviceRole.objects.all()[0]
dt=DeviceType.objects.all()[0]
site=Site.objects.all()[0]
dev1=Device(name='dev1',role=role,site=site,device_type=dt)
dev1.full_clean()
nic1=Interface(name='nic1',device=dev1,enabled=True,)
nic1.full_clean()
dev1.save()
nic1.save()
dev1.save()  # with this will trigger the bug
  1. check GUI -> Devices -> Configure Table -> Add Interface Columns -> It shows '0'.
  2. check GUI -> Devices -> dev1 -> Interfaces tab shows '1' -> in the Interfaces, nic1 is created.

Expected Behavior

For VirtualMachine:
Interface Column should shows '1' instead of '0'
Interface Tab should shows '1' instead of '0'

For Devices:
Interface Column should shows '1' instead of '0'

Observed Behavior

The interface_count is not synced from interfaces.count() as it should after objects.save(), interface tab does not show the correct interface count.

Originally created by @kenneth-sfv on GitHub (Oct 14, 2025). ### NetBox Edition NetBox Community ### NetBox Version v4.4.2 ### Python Version 3.12 ### Steps to Reproduce **For VirtualMachine:** 1. In nbshell ``` python # ./manage.py nbshell from virtualization.models import Cluster, VirtualMachine, VMInterface cluster = Cluster.objects.get(name="cluster1") vm = VirtualMachine(name="vm1", cluster=cluster) vm.full_clean() vm.save() #Saving vm to be able to add nic below nic1 = VMInterface(virtual_machine=vm, name="nic1") nic1.full_clean() nic1.save() vm.save() # with this will trigger the bug ``` 2.Check GUI -> Virtual Machines -> Configure Table -> Add Interface Columns -> It shows '0'. 3.Check GUI -> Virtual Machines -> vm1 -> Interfaces tab shows nothing, -> in interface tab, nic1 is created. **For Devices:** 1. in nbshell ``` python # manage.py nbshell from dcim.models import DeviceRole, DeviceType,Site,Device,Interface role=DeviceRole.objects.all()[0] dt=DeviceType.objects.all()[0] site=Site.objects.all()[0] dev1=Device(name='dev1',role=role,site=site,device_type=dt) dev1.full_clean() nic1=Interface(name='nic1',device=dev1,enabled=True,) nic1.full_clean() dev1.save() nic1.save() dev1.save() # with this will trigger the bug ``` 2. check GUI -> Devices -> Configure Table -> Add Interface Columns -> It shows '0'. 3. check GUI -> Devices -> dev1 -> Interfaces tab shows '1' -> in the Interfaces, nic1 is created. ### Expected Behavior For VirtualMachine: Interface Column should shows '1' instead of '0' Interface Tab should shows '1' instead of '0' For Devices: Interface Column should shows '1' instead of '0' ### Observed Behavior The interface_count is not synced from interfaces.count() as it should after objects.save(), interface tab does not show the correct interface count.
adam added the type: bugpending closurestatus: revisions needednetbox labels 2025-12-29 21:49:01 +01:00
adam closed this issue 2025-12-29 21:49:03 +01:00
Author
Owner

@pheus commented on GitHub (Oct 14, 2025):

Thanks for opening the issue and sharing the details!

Quick formatting note: a few of the code snippets in the description didn’t render. Using fenced code blocks (triple backticks or tildes) will make commands and Python examples much easier to read for others.

For your specific case, when working in nbshell (or a Custom Script), instantiate the model in Python, run validation with full_clean() (which includes the model’s clean() and field validation), then call save(). This catches validation errors before anything is written to the database. (Using objects.create() won’t run full_clean().)

Example (nbshell):

# ./manage.py nbshell
from virtualization.models import Cluster, VirtualMachine, VMInterface

cluster = Cluster.objects.get(name="Your Cluster")
vm = VirtualMachine(name="vm1", cluster=cluster)
vm.full_clean()  # runs field & model validation
vm.save()

# Create the interface explicitly so you can validate it, too
nic1 = VMInterface(virtual_machine=vm, name="nic1")
nic1.full_clean()
nic1.save()

You can find a longer working example here:
https://github.com/netbox-community/customizations/blob/master/scripts/create_vm.py

If you still run into trouble after validating and saving as above, please share the exact snippet you ran (inside a fenced code block).

@pheus commented on GitHub (Oct 14, 2025): Thanks for opening the issue and sharing the details! *Quick formatting note:* a few of the code snippets in the description didn’t render. Using fenced code blocks (triple backticks or tildes) will make commands and Python examples much easier to read for others. For your specific case, when working in `nbshell` (or a Custom Script), instantiate the model in Python, run validation with `full_clean()` (which includes the model’s `clean()` and field validation), then call `save()`. This catches validation errors before anything is written to the database. (Using `objects.create()` won’t run `full_clean()`.) **Example (`nbshell`):** ```python # ./manage.py nbshell from virtualization.models import Cluster, VirtualMachine, VMInterface cluster = Cluster.objects.get(name="Your Cluster") vm = VirtualMachine(name="vm1", cluster=cluster) vm.full_clean() # runs field & model validation vm.save() # Create the interface explicitly so you can validate it, too nic1 = VMInterface(virtual_machine=vm, name="nic1") nic1.full_clean() nic1.save() ``` You can find a longer working example here: https://github.com/netbox-community/customizations/blob/master/scripts/create_vm.py If you still run into trouble after validating and saving as above, please share the exact snippet you ran (inside a fenced code block).
Author
Owner

@kenneth-sfv commented on GitHub (Oct 15, 2025):

@pheus
Thanks for quick reply!
I am learning how to post the issues in GitHub , this is 2nd time so apologise for the bad formatting and thanks a lot for your tips.

I have updated it and now it should look better.

Image Image Image
@kenneth-sfv commented on GitHub (Oct 15, 2025): @pheus Thanks for quick reply! I am learning how to post the issues in GitHub , this is 2nd time so apologise for the bad formatting and thanks a lot for your tips. I have updated it and now it should look better. <img width="1298" height="189" alt="Image" src="https://github.com/user-attachments/assets/aead0e88-9dac-4dc4-b641-f58fe75cd529" /> <img width="1426" height="366" alt="Image" src="https://github.com/user-attachments/assets/3a6bbd51-7070-43d3-a36f-f0c1b3b81edc" /> <img width="1123" height="262" alt="Image" src="https://github.com/user-attachments/assets/38ca9073-4227-43d5-8ab4-1f25ee714b7b" />
Author
Owner

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

Thanks for updating the issue - it reads much clearer now, and no worries at all about the earlier formatting. (Tip for next time: the GitHub editor has a Preview tab next to Write, which makes it easy to spot formatting issues before posting.)

On the behavior you’re seeing, I think this is likely expected rather than a bug. What’s happening is a classic “stale instance” situation:

  • vm.save() writes the in‑memory state of your VirtualMachine instance back to the database.
  • After you create and save a VMInterface, NetBox updates the VM’s related counters in the database.
  • However, your existing vm Python object doesn’t know about those fresh DB changes yet. If you call vm.save() again without refreshing it, you can overwrite the DB’s updated counter with the older value still held in memory.

Safer patterns

  • If you didn’t change any fields on vm after creating the interface, you can simply skip the final vm.save().

  • If you did change the VM and need to save it afterward, first refresh it from the database so you pick up the latest counters:

    vm.refresh_from_db()
    # then make your changes and save only the fields you modified
    vm.description = "Some note"
    vm.save(update_fields=["description"])
    

Minimal example (nbshell)

# create and validate the VM
vm = VirtualMachine(name="vm1", cluster=cluster, site=site)
vm.full_clean()
vm.save()

# create and validate the interface
nic1 = VMInterface(virtual_machine=vm, name="nic1")
nic1.full_clean()
nic1.save()

# only if you need to modify vm after creating the interface:
vm.refresh_from_db()                # pull in updated counters
vm.comments = "Post‑creation update"
vm.save(update_fields=["comments"]) # avoid touching unrelated fields

I’m not a maintainer (just trying to be helpful) so please take this as guidance and not an authoritative ruling. If a maintainer feels this should be handled differently (or documented more clearly), I’m happy to stand corrected.
Thanks again for taking the time to improve the report!

@pheus commented on GitHub (Oct 15, 2025): Thanks for updating the issue - it reads much clearer now, and no worries at all about the earlier formatting. (Tip for next time: the GitHub editor has a **Preview** tab next to **Write**, which makes it easy to spot formatting issues before posting.) On the behavior you’re seeing, I think this is likely expected rather than a bug. What’s happening is a classic “stale instance” situation: - `vm.save()` writes the **in‑memory** state of your `VirtualMachine` instance back to the database. - After you create and save a `VMInterface`, NetBox updates the VM’s related counters in the **database**. - However, your existing `vm` Python object doesn’t know about those fresh DB changes yet. If you call `vm.save()` again without refreshing it, you can overwrite the DB’s updated counter with the older value still held in memory. **Safer patterns** - If you didn’t change any fields on `vm` after creating the interface, you can simply **skip** the final `vm.save()`. - If you *did* change the VM and need to save it afterward, first **refresh** it from the database so you pick up the latest counters: ```python vm.refresh_from_db() # then make your changes and save only the fields you modified vm.description = "Some note" vm.save(update_fields=["description"]) ``` **Minimal example (nbshell)** ```python # create and validate the VM vm = VirtualMachine(name="vm1", cluster=cluster, site=site) vm.full_clean() vm.save() # create and validate the interface nic1 = VMInterface(virtual_machine=vm, name="nic1") nic1.full_clean() nic1.save() # only if you need to modify vm after creating the interface: vm.refresh_from_db() # pull in updated counters vm.comments = "Post‑creation update" vm.save(update_fields=["comments"]) # avoid touching unrelated fields ``` I’m not a maintainer (just trying to be helpful) so please take this as guidance and not an authoritative ruling. If a maintainer feels this should be handled differently (or documented more clearly), I’m happy to stand corrected. Thanks again for taking the time to improve the report!
Author
Owner

@kenneth-sfv commented on GitHub (Oct 16, 2025):

Thanks again for the details explanation!! It is very appreciated for the fix as well.
I think the issue that we have is exactly what you mentioned as 'stale instance' situation there, it make more sense to me now.
But there is still one thing puzzles me that is why the device.save has slightly different behavior, because even I did device.save() after nic.save() , on the device interface tab it shows correct number '1'.

@kenneth-sfv commented on GitHub (Oct 16, 2025): Thanks again for the details explanation!! It is very appreciated for the fix as well. I think the issue that we have is exactly what you mentioned as 'stale instance' situation there, it make more sense to me now. But there is still one thing puzzles me that is why the device.save has slightly different behavior, because even I did device.save() after nic.save() , on the device interface tab it shows correct number '1'.
Author
Owner

@pheus commented on GitHub (Oct 16, 2025):

Thanks for the update.

There is a difference between the Device and VirtualMachine models (Devices are based on DeviceType), so their behavior can differ. Digging into the exact root cause would take some time.

If you feel it’s worth pursuing, please update the issue to note the Device vs. VM difference and your specific use case. If a maintainer agrees, they can triage it and open it for work.

@pheus commented on GitHub (Oct 16, 2025): Thanks for the update. There is a difference between the `Device` and `VirtualMachine` models (Devices are based on `DeviceType`), so their behavior can differ. Digging into the exact root cause would take some time. If you feel it’s worth pursuing, please update the issue to note the Device vs. VM difference and your specific use case. If a maintainer agrees, they can triage it and open it for work.
Author
Owner

@github-actions[bot] commented on GitHub (Oct 24, 2025):

This is a reminder that additional information is needed in order to further triage this issue. If the requested details are not provided, the issue will soon be closed automatically.

@github-actions[bot] commented on GitHub (Oct 24, 2025): This is a reminder that additional information is needed in order to further triage this issue. If the requested details are not provided, the issue will soon be closed automatically.
Author
Owner

@github-actions[bot] commented on GitHub (Oct 31, 2025):

This issue is being closed as no further information has been provided. If you would like to revisit this topic, please first modify your original post to include all the requested detail, and then ask that the issue be reopened.

@github-actions[bot] commented on GitHub (Oct 31, 2025): This issue is being closed as no further information has been provided. If you would like to revisit this topic, please first modify your original post to include all the requested detail, and then ask that the issue be reopened.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11723