Skip to content

Duplicate site_id index on TopologySavedView breaks netbox-branching provisioning (index rename collision) #69

@Kani999

Description

@Kani999

Summary

When netbox-branching is installed alongside this plugin, provisioning a branch fails while normalizing the indexes of netbox_map_topologysavedview. The table has two indexes on the site_id column with identical definitions, and branching's index-rename step tries to rename both of them to the same target name, causing a collision.

Observed behavior

Branch provisioning fails with (worker + postgres logs):

netbox-worker-1 | DEBUG:netbox_branching.branch.provision:ALTER INDEX branch_4ms91w5d.netbox_map_topologysavedview_site_id_idx RENAME TO netbox_map_topologysavedview_site_id_a2d875ab
postgres-1      | ERROR:  relation "netbox_map_topologysavedview_site_id_a2d875ab" already exists
postgres-1      | STATEMENT:  ALTER INDEX branch_4ms91w5d.netbox_map_topologysavedview_site_id_idx1 RENAME TO netbox_map_topologysavedview_site_id_a2d875ab
netbox-worker-1 | ERROR:netbox_branching.branch.provision:ALTER INDEX branch_4ms91w5d.netbox_map_topologysavedview_site_id_idx1 RENAME TO netbox_map_topologysavedview_site_id_a2d875ab
netbox-worker-1 | ERROR:netbox_branching.branch.provision:relation "netbox_map_topologysavedview_site_id_a2d875ab" already exists

The branch is left in a FAILED state and must be deleted.

Steps to reproduce

  1. Install NetBox with both netbox-map and netbox-branching enabled.
  2. Run migrations.
  3. Create a branch (Plugins → Branching → Branches → Add).
  4. Provisioning fails with the error above.

Environment in which this was seen:

  • NetBox: 4.x (Docker), PostgreSQL 18.3
  • netbox-branching: v1.0.3
  • netbox-map: current main (≈ v0.12.0)

Root cause: two indexes on site_id

TopologySavedView is created by a hand-written RunSQL migration, 0017_topologysavedview.py. The raw SQL manually creates an index on site_id:

CREATE INDEX IF NOT EXISTS "netbox_map_topologysavedview_site_id"
    ON "netbox_map_topologysavedview" ("site_id");

…while the migration's state_operations declares site as a normal ForeignKey:

('site', models.ForeignKey(blank=True, null=True,
    on_delete=django.db.models.deletion.SET_NULL,
    related_name='topology_views', to='dcim.site')),

A ForeignKey has db_index=True by default, so Django's model state also expects an index on site_id — its deterministic hashed name is netbox_map_topologysavedview_site_id_a2d875ab. Because the manual CREATE INDEX used a different name (netbox_map_topologysavedview_site_id), the database ends up with two indexes on site_id, both btree (site_id):

  1. netbox_map_topologysavedview_site_id — manual, from the RunSQL block
  2. netbox_map_topologysavedview_site_id_a2d875ab — implicit FK index from the model state

This is confirmed directly in psql — the table carries the manual index name, and Django/branching expect the _a2d875ab name; both resolve to the same (site_id) definition.

Why branching then fails

netbox-branching normalizes branch-schema index names by matching each branch index to the main schema by index definition, then renaming it (branches.py L1026–L1052):

# Find the matching index in main based on its table & definition
cursor.execute(
    "SELECT indexname FROM pg_indexes WHERE schemaname=%s AND tablename=%s AND indexdef LIKE %s",
    [main_schema, index.tablename, f'% {definition}']
)
...
sql = f"ALTER INDEX {schema}.{index.indexname} RENAME TO {new_name}"

CREATE TABLE … (LIKE main INCLUDING INDEXES) copies both site indexes into the branch, where Postgres auto-renames them …_site_id_idx and …_site_id_idx1. When branching looks up the matching main name by definition, both indexes have the identical definition btree (site_id), so the query returns the same main name (…_a2d875ab) for both. The first rename succeeds; the second collides:

RENAME …_site_id_idx  → …_a2d875ab   ✅
RENAME …_site_id_idx1 → …_a2d875ab   ❌  relation already exists

Prior art (this is a known plugin-side pattern)

netbox-branching has seen this exact failure mode before and treats it as a plugin issue — having two indexes on the same column makes branching's definition-based normalization ambiguous:

Impact

With netbox-map installed, netbox-branching cannot provision any branch — provisioning aborts during index normalization of netbox_map_topologysavedview, before the branch is usable. This makes the two plugins effectively incompatible until the redundant site_id index is removed.

Filing for visibility; happy to provide additional psql output (\d netbox_map_topologysavedview) if useful.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions