OpenNHP/opennhp · error
keystore: find agent by pubkey
Error message
keystore: find agent by pubkey: %w
What it means
FindAgentByPublicKey wraps failures of the COUNT(*) query that checks whether a base64 public key belongs to an active, non-expired agent. Only DB-level failures produce this error; a zero count returns (false, nil). It is consulted by the noise-layer peer validation fallback, so an error here can block peer authentication.
Solutions
- Log the wrapped driver error to determine if it is 'no such table', 'database is locked', or 'database is closed'.
- Run schema migration before starting the noise-layer listener that calls this function.
- Enable WAL mode and busy_timeout on the SQLite handle to reduce lock contention.
- Confirm the server process owns/opens the DB file it is configured to use.
- Retry transient lock errors with backoff at the caller (peer validation) level.
Example fix
null
Defensive patterns
Strategy: retry
Validate before calling
if pubKeyBase64 == "" { return false, errors.New("empty public key") }
if err := db.Ping(); err != nil { return false, err } Type guard
ok, err := store.FindAgentByPublicKey(pubKey)
if err != nil {
// fail closed, but log the wrapped cause
log.Errorf("peer validation failed: %v", err)
return false
} Try / catch
ok, err := store.FindAgentByPublicKey(pub)
if err != nil {
if isLockTimeout(err) { return store.FindAgentByPublicKey(pub) } // one retry
return false, err
} Prevention
- Configure SQLite busy_timeout so short write locks do not fail reads
- Ensure migrations run before the noise listener starts accepting peers
- Fail closed on error but alert loudly — this gate controls peer authentication
- Monitor DB lock latency to catch contention early
When it happens
Trigger: Calling FindAgentByPublicKey(pubKeyBase64) when the DB connection is closed, the agent_keys table is missing, the database is locked, or the driver returns a general query error.
Common situations: SQLite file locked during backup jobs; schema mismatch after an upgrade; disk-full conditions preventing even a SELECT from executing; running the server against an uninitialized config path.
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: get agent key
- keystore: check agent registered
- keystore: get agent key expiry
- keystore: sweep expired
- keystore: sweep rows affected
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/aa35b7b1cd5f729e.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/keystore.go:464
rec.ExpiresAt = &expiresAt.Int64
}
return rec, nil
}
// FindAgentByPublicKey returns true if the given base64-encoded public key
// is registered, active, and not expired. This is the gate consulted by
// the noise-layer peer validation fallback; an expired key behaves as if
// the agent were never registered.
func (s *AgentKeyStore) FindAgentByPublicKey(pubKeyBase64 string) (bool, error) {
var count int
err := s.db.QueryRow(
`SELECT COUNT(*) FROM agent_keys
WHERE public_key = ? AND active = 1
AND (expires_at IS NULL OR expires_at > ?)`,
pubKeyBase64, time.Now().Unix(),
).Scan(&count)
if err != nil {
return false, fmt.Errorf("keystore: find agent by pubkey: %w", err)
}
return count > 0, nil
}
// IsAgentRegistered returns true if the user+device pair has an active,
// non-expired registered key.
func (s *AgentKeyStore) IsAgentRegistered(userId, deviceId string) (bool, error) {
var count int
err := s.db.QueryRow(
`SELECT COUNT(*) FROM agent_keys
WHERE usr_id = ? AND dev_id = ? AND active = 1
AND (expires_at IS NULL OR expires_at > ?)`,
userId, deviceId, time.Now().Unix(),
).Scan(&count)
if err != nil {
return false, fmt.Errorf("keystore: check agent registered: %w", err)
}
return count > 0, nilView on GitHub (pinned to 6e04ca5ff0)