{"record":{"id":"fd5fa6f1b3bd4c2e","repo":"OpenNHP/opennhp","slug":"keystore-query-pubkey-conflict-w","errorCode":null,"errorMessage":"keystore: query pubkey conflict: %w","messagePattern":"keystore: query pubkey conflict: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/keystore.go","lineNumber":392,"sourceCode":"\tnow := time.Now().Unix()\n\n\t// Check for public key conflict (same key, different user/device).\n\tvar existingUserId string\n\terr := s.db.QueryRow(\n\t\t`SELECT usr_id FROM agent_keys WHERE public_key = ? AND active = 1`,\n\t\tpubKey,\n\t).Scan(&existingUserId)\n\tif err == nil {\n\t\tif existingUserId != userId {\n\t\t\treturn common.ErrPublicKeyAlreadyRegistered\n\t\t}\n\t\t// Same user, same key — idempotent, no-op. Do NOT reset the\n\t\t// expiry clock: a re-register attempt for the same key should\n\t\t// not extend an already-issued lifetime.\n\t\treturn nil\n\t}\n\tif err != sql.ErrNoRows {\n\t\treturn fmt.Errorf(\"keystore: query pubkey conflict: %w\", err)\n\t}\n\n\t// Compute expires_at for this registration.\n\tvar expiresAt sql.NullInt64\n\tif ttlSeconds > 0 {\n\t\texpiresAt = sql.NullInt64{Int64: now + ttlSeconds, Valid: true}\n\t}\n\n\t// Upsert: insert or update on (usr_id, dev_id) conflict. Both fresh\n\t// inserts and key rotations (including cipher scheme switches) reset\n\t// the clock.\n\t_, err = s.db.Exec(\n\t\t`INSERT INTO agent_keys (usr_id, dev_id, public_key, cipher, created_at, expires_at, active)\n\t\t VALUES (?, ?, ?, ?, ?, ?, 1)\n\t\t ON CONFLICT(usr_id, dev_id) DO UPDATE SET\n\t\t   public_key = excluded.public_key,\n\t\t   cipher     = excluded.cipher,\n\t\t   created_at = excluded.created_at,","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/keystore.go#L374-L410","documentation":"RegisterAgentKey probes for an existing key for the user+device; if the SELECT fails with anything other than ErrNoRows, it wraps as 'keystore: query pubkey conflict'. ErrNoRows is expected (new registration) — this wrapper signals a database-level failure.","triggerScenarios":"The conflict-check SELECT fails: SQLITE_BUSY on contended writes, database corruption, or a table/column mismatch (agent_keys schema changed externally).","commonSituations":"Manual migrations or a stale binary running against a newer/older schema, crash-corrupted files, or read-only mounts failing mid-query under WAL.","solutions":["Log and inspect the wrapped SQLite error code.","Confirm the running binary matches the schema produced by migrate() — restart to run migrations.","If SQLITE_BUSY, lower write concurrency or move to a multi-writer database backend.","Run PRAGMA integrity_check if corruption is suspected."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := store.RegisterAgentKey(u, d, pk, cs, ttl); err != nil {\n    if strings.Contains(err.Error(), \"query pubkey conflict\") {\n        log.Error(\"registration db failure: %v\", err)\n    }\n    return err\n}","preventionTips":["Restart daemons after schema changes so migrate() runs","Pin driver and SQLite version; avoid swapping drivers silently","Back up keystore.db before manual maintenance"],"tags":["go","sqlite","query","registration"],"backgroundTag":"database-query-failed","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}