Skip to content

Stale database table reference after deleting a multiobject field causes ProgrammingError on related object deletion #535

@flmfuchs

Description

@flmfuchs

Plugin Version

0.5.1

NetBox Version

4.6.1-Docker-5.0.1

Python Version

3.14.4

Steps to Reproduce

After deleting a multiobject field from a Custom Object Type, the plugin leaves a stale reference in the database. When trying to delete a NetBox object that was previously used as a relation target of that field, a ProgrammingError is raised because the plugin still queries the (now non-existent) M2M table of the deleted field.

Create a Custom Object Type (e.g. certificate_location)
Add a multiobject field to it targeting an IPAM model (e.g. ipam.service) — field name e.g. ssl_service2
Delete the field via the plugin UI
Try to delete any object of the previously targeted model (e.g. any IPAM service)

Expected Behavior

Deleting the field cleanly removes all database artifacts. Deleting a related NetBox object succeeds without errors.

Observed Behavior

django.db.utils.ProgrammingError: relation "custom_objects_2_ssl_service2" does not exist
LINE 1: ... "custom_objects_2_ssl_service2"."target_id" FROM "custom_ob...

GET /ipam/services/5/delete/?return_url=/ipam/services/
The plugin queries the M2M table of the deleted field when checking for related objects during deletion.

Investigation

netbox_custom_objects_customobjecttypefield contains no entry for ssl_service2 — the field record was correctly deleted
\dt custom_objects* shows the M2M table custom_objects_2_ssl_service2 is missing — it was either never created or already dropped
netbox_custom_objects_customobjecttypefield_related_object_93dc contains no stale entries for the deleted field
The source of the stale reference that causes the plugin to still query the missing table could not be identified

Workaround

CREATE TABLE custom_objects_2_ssl_service2 (
    id        integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    source_id bigint NOT NULL,
    target_id bigint NOT NULL,
    UNIQUE (source_id, target_id),
    FOREIGN KEY (source_id)
        REFERENCES custom_objects_2(id) DEFERRABLE INITIALLY DEFERRED,
    FOREIGN KEY (target_id)
        REFERENCES ipam_service(id) DEFERRABLE INITIALLY DEFERRED
);
CREATE INDEX ON custom_objects_2_ssl_service2 (source_id);
CREATE INDEX ON custom_objects_2_ssl_service2 (target_id);

The table remains empty — the deletion proceeds normally.

Additional context

The table naming convention custom_objects_{type_id}_{field_name} uses target_id as the FK column for direct object relations, in contrast to the polymorphic multiobject fields which use content_type_id + object_id. This distinction was discovered during the investigation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions