From f950511e3e2e5829b9046c7f347cdd3bd3c2d6c5 Mon Sep 17 00:00:00 2001 From: Mike Swanson Date: Mon, 1 Jun 2026 09:50:34 -0700 Subject: [PATCH] fix(server): bind machine_uid upsert ON CONFLICT to the partial index (WHERE machine_uid IS NOT NULL) Bare ON CONFLICT (machine_uid) could not bind to migration 008's partial unique index, so no connect_machines row was persisted for any agent reporting a machine_uid. Confirmed live on 172.16.3.30 with a signed 0.3.0 test agent. --- server/migrations/008_machine_uid.sql | 8 ++++++-- server/src/db/machines.rs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/server/migrations/008_machine_uid.sql b/server/migrations/008_machine_uid.sql index 8488031..3af40f3 100644 --- a/server/migrations/008_machine_uid.sql +++ b/server/migrations/008_machine_uid.sql @@ -34,8 +34,12 @@ ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS machine_uid TEXT; -- 2. Enforce one row per machine_uid, but ONLY for rows that actually have one. -- A partial UNIQUE index (WHERE machine_uid IS NOT NULL) lets unlimited legacy --- NULL rows coexist while making a non-null machine_uid a true dedup key — this --- is what upsert_machine's `ON CONFLICT (machine_uid)` arbiter binds to. +-- NULL rows coexist while making a non-null machine_uid a true dedup key. Because +-- this index is PARTIAL, Postgres only binds an ON CONFLICT inference clause to it +-- when the clause REPEATS the same predicate: upsert_machine's arbiter must be +-- `ON CONFLICT (machine_uid) WHERE machine_uid IS NOT NULL` (a bare +-- `ON CONFLICT (machine_uid)` raises "no unique or exclusion constraint matching +-- the ON CONFLICT specification" at runtime and persists no row). CREATE UNIQUE INDEX IF NOT EXISTS idx_connect_machines_machine_uid ON connect_machines (machine_uid) WHERE machine_uid IS NOT NULL; diff --git a/server/src/db/machines.rs b/server/src/db/machines.rs index b6b65d6..901260b 100644 --- a/server/src/db/machines.rs +++ b/server/src/db/machines.rs @@ -166,7 +166,7 @@ pub async fn upsert_machine( r#" INSERT INTO connect_machines (agent_id, hostname, is_persistent, status, last_seen, machine_uid) VALUES ($1, $2, $3, 'online', NOW(), $4) - ON CONFLICT (machine_uid) DO UPDATE SET + ON CONFLICT (machine_uid) WHERE machine_uid IS NOT NULL DO UPDATE SET agent_id = EXCLUDED.agent_id, hostname = EXCLUDED.hostname, status = 'online',