AutoSyncRecord not cleaned up when detaching Config Template from Data Source #533

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

Originally created by @jnovinger on 1/19/2026

NetBox Edition

NetBox Community

NetBox Version

v4.4.7

Python Version

3.12

Steps to Reproduce

  1. Create a Git Data Source containing at least two Jinja2 files (e.g., a.j2, b.j2)
  2. Run sync on the Data Source
  3. Create two Config Templates:
    • CT-A → Data Source = , Data File = a.j2, Auto sync enabled
    • CT-B → Data Source = , Data File = b.j2, Auto sync enabled
  4. Verify sync works by changing b.j2, commit/push, run Data Source sync, confirm CT-B updates
  5. Edit CT-A and detach it from the Data Source:
    • Set data_source = NULL
    • Set data_file = NULL
    • Set auto_sync_enabled = False
    • Save the Config Template
  6. Make a manual content edit to CT-A
  7. Change b.j2 again in git, commit/push, run Data Source sync

Expected Behavior

When a Config Template is detached from a Data Source (data_source and data_file cleared, auto_sync_enabled disabled), the associated AutoSyncRecord should be automatically cleaned up. The Data Source sync should continue successfully, syncing other valid objects (like CT-B).

Observed Behavior

The Data Source sync job fails with an error (e.g., 'NoneType' object has no attribute 'data_as_string') and prevents other objects from syncing.

The stale AutoSyncRecord remains even though the Config Template is detached:

from extras.models import ConfigTemplate
from django.contrib.contenttypes.models import ContentType
from core.models import AutoSyncRecord

ct = ConfigTemplate.objects.get(name="CT-A")
ct.data_source_id, ct.data_file_id, ct.auto_sync_enabled   
# (None, None, False)

ct_type = ContentType.objects.get_for_model(ConfigTemplate)
AutoSyncRecord.objects.filter(object_type=ct_type, object_id=ct.pk).values()
# Returns record with datafile_id still set

Deleting the stale AutoSyncRecord manually resolves the issue:

AutoSyncRecord.objects.filter(object_type=ct_type, object_id=ct.pk).delete()

After deletion, Data Source sync succeeds and remaining templates sync as expected.

*Originally created by @jnovinger on 1/19/2026* ### NetBox Edition NetBox Community ### NetBox Version v4.4.7 ### Python Version 3.12 ### Steps to Reproduce 1. Create a Git Data Source containing at least two Jinja2 files (e.g., a.j2, b.j2) 2. Run sync on the Data Source 3. Create two Config Templates: - CT-A → Data Source = <git>, Data File = a.j2, Auto sync enabled - CT-B → Data Source = <git>, Data File = b.j2, Auto sync enabled 4. Verify sync works by changing b.j2, commit/push, run Data Source sync, confirm CT-B updates 5. Edit CT-A and detach it from the Data Source: - Set data_source = NULL - Set data_file = NULL - Set auto_sync_enabled = False - Save the Config Template 6. Make a manual content edit to CT-A 7. Change b.j2 again in git, commit/push, run Data Source sync ### Expected Behavior When a Config Template is detached from a Data Source (data_source and data_file cleared, auto_sync_enabled disabled), the associated AutoSyncRecord should be automatically cleaned up. The Data Source sync should continue successfully, syncing other valid objects (like CT-B). ### Observed Behavior The Data Source sync job fails with an error (e.g., 'NoneType' object has no attribute 'data_as_string') and prevents other objects from syncing. The stale AutoSyncRecord remains even though the Config Template is detached: ```python from extras.models import ConfigTemplate from django.contrib.contenttypes.models import ContentType from core.models import AutoSyncRecord ct = ConfigTemplate.objects.get(name="CT-A") ct.data_source_id, ct.data_file_id, ct.auto_sync_enabled # (None, None, False) ct_type = ContentType.objects.get_for_model(ConfigTemplate) AutoSyncRecord.objects.filter(object_type=ct_type, object_id=ct.pk).values() # Returns record with datafile_id still set ``` Deleting the stale AutoSyncRecord manually resolves the issue: ```python AutoSyncRecord.objects.filter(object_type=ct_type, object_id=ct.pk).delete() ``` After deletion, Data Source sync succeeds and remaining templates sync as expected.
MrUnknownDE added the severity: lowstatus: acceptedtype: 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: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowseverity: lowstatus: 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: 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: acceptedtype: 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: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bug labels 2026-04-05 16:40:40 +02:00
Sign in to join this conversation.
No Label 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 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 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 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#533