OpenNHP/opennhp · error
keystore: query pubkey conflict
Error message
keystore: query pubkey conflict: %w
What it means
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.
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.
Defensive patterns
Strategy: try-catch
Try / catch
if err := store.RegisterAgentKey(u, d, pk, cs, ttl); err != nil {
if strings.Contains(err.Error(), "query pubkey conflict") {
log.Error("registration db failure: %v", err)
}
return err
} Prevention
- Restart daemons after schema changes so migrate() runs
- Pin driver and SQLite version; avoid swapping drivers silently
- Back up keystore.db before manual maintenance
When it happens
Trigger: The conflict-check SELECT fails: SQLITE_BUSY on contended writes, database corruption, or a table/column mismatch (agent_keys schema changed externally).
Common situations: Manual migrations or a stale binary running against a newer/older schema, crash-corrupted files, or read-only mounts failing mid-query under WAL.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- keystore: query otp
- keystore: query pending otp
- keystore: insert agent key
- keystore: check agent registered
- AuthServiceId is required
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/fd5fa6f1b3bd4c2e.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/keystore.go:392
now := time.Now().Unix()
// Check for public key conflict (same key, different user/device).
var existingUserId string
err := s.db.QueryRow(
`SELECT usr_id FROM agent_keys WHERE public_key = ? AND active = 1`,
pubKey,
).Scan(&existingUserId)
if err == nil {
if existingUserId != userId {
return common.ErrPublicKeyAlreadyRegistered
}
// Same user, same key — idempotent, no-op. Do NOT reset the
// expiry clock: a re-register attempt for the same key should
// not extend an already-issued lifetime.
return nil
}
if err != sql.ErrNoRows {
return fmt.Errorf("keystore: query pubkey conflict: %w", err)
}
// Compute expires_at for this registration.
var expiresAt sql.NullInt64
if ttlSeconds > 0 {
expiresAt = sql.NullInt64{Int64: now + ttlSeconds, Valid: true}
}
// Upsert: insert or update on (usr_id, dev_id) conflict. Both fresh
// inserts and key rotations (including cipher scheme switches) reset
// the clock.
_, err = s.db.Exec(
`INSERT INTO agent_keys (usr_id, dev_id, public_key, cipher, created_at, expires_at, active)
VALUES (?, ?, ?, ?, ?, ?, 1)
ON CONFLICT(usr_id, dev_id) DO UPDATE SET
public_key = excluded.public_key,
cipher = excluded.cipher,
created_at = excluded.created_at,View on GitHub (pinned to 6e04ca5ff0)