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
- Install NetBox with both
netbox-map and netbox-branching enabled.
- Run migrations.
- Create a branch (Plugins → Branching → Branches → Add).
- 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):
netbox_map_topologysavedview_site_id — manual, from the RunSQL block
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.
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 thesite_idcolumn 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):
The branch is left in a
FAILEDstate and must be deleted.Steps to reproduce
netbox-mapandnetbox-branchingenabled.Environment in which this was seen:
main(≈ v0.12.0)Root cause: two indexes on
site_idTopologySavedViewis created by a hand-writtenRunSQLmigration,0017_topologysavedview.py. The raw SQL manually creates an index onsite_id:…while the migration's
state_operationsdeclaressiteas a normalForeignKey:A
ForeignKeyhasdb_index=Trueby default, so Django's model state also expects an index onsite_id— its deterministic hashed name isnetbox_map_topologysavedview_site_id_a2d875ab. Because the manualCREATE INDEXused a different name (netbox_map_topologysavedview_site_id), the database ends up with two indexes onsite_id, bothbtree (site_id):netbox_map_topologysavedview_site_id— manual, from the RunSQL blocknetbox_map_topologysavedview_site_id_a2d875ab— implicit FK index from the model stateThis is confirmed directly in
psql— the table carries the manual index name, and Django/branching expect the_a2d875abname; 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.pyL1026–L1052):CREATE TABLE … (LIKE main INCLUDING INDEXES)copies both site indexes into the branch, where Postgres auto-renames them…_site_id_idxand…_site_id_idx1. When branching looks up the matching main name by definition, both indexes have the identical definitionbtree (site_id), so the query returns the same main name (…_a2d875ab) for both. The first rename succeeds; the second collides: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-mapinstalled, netbox-branching cannot provision any branch — provisioning aborts during index normalization ofnetbox_map_topologysavedview, before the branch is usable. This makes the two plugins effectively incompatible until the redundantsite_idindex is removed.Filing for visibility; happy to provide additional
psqloutput (\d netbox_map_topologysavedview) if useful.