From 40999b0b408ccbe1168fd072ddcb6945e9d4f660 Mon Sep 17 00:00:00 2001 From: dtoro Date: Fri, 10 Jul 2026 19:26:48 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20knowledge/recent=20returned=20empty=20it?= =?UTF-8?q?ems=20=E2=80=94=20timestamptz=20couldn't=20scan=20into=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verified live immediately after deploying: the endpoint returned 200 with correct-looking stats (total=56, agent_authored=2) but items=[] always, regardless of limit/source. Root cause: pgx v5 can't scan a timestamptz column directly into a Go string — Scan() errored on every single row, and that error was silently swallowed by a bare `continue`, so every row was dropped with no trace in the logs. Fixed by casting updated_at::text in the SQL (matching how every other handler in this codebase already returns timestamps) and logging scan failures instead of swallowing them, so this class of bug can't hide silently again. Co-Authored-By: Claude Opus 4.8 --- internal/httpapi/knowledge.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/httpapi/knowledge.go b/internal/httpapi/knowledge.go index ed3735e..f63e1c0 100644 --- a/internal/httpapi/knowledge.go +++ b/internal/httpapi/knowledge.go @@ -3,6 +3,7 @@ package httpapi import ( "context" "encoding/json" + "log/slog" "net/http" "strconv" @@ -36,8 +37,13 @@ func (s *Server) serveRecentKnowledge(w http.ResponseWriter, req *http.Request) AgentAuthored bool `json:"agent_authored"` } + // updated_at is cast to text in SQL — pgx v5 can't scan a timestamptz + // directly into a Go string (needs time.Time or an explicit cast), and + // that scan error was being silently swallowed below (every row skipped, + // endpoint returned 200 with an empty list and correct-looking stats + // since the stats query doesn't scan any timestamp column — found live). rows, err := s.pool.Query(ctx, ` - SELECT e.slug, ke.title, e.type, COALESCE(ke.source,''), ke.tags, ke.updated_at + SELECT e.slug, ke.title, e.type, COALESCE(ke.source,''), ke.tags, ke.updated_at::text FROM knowledge_entities ke JOIN entities e ON e.id = ke.entity_id WHERE ($1 = '' OR ke.source = $1) @@ -53,6 +59,7 @@ func (s *Server) serveRecentKnowledge(w http.ResponseWriter, req *http.Request) var it item var src string if err := rows.Scan(&it.Slug, &it.Title, &it.Kind, &src, &it.Tags, &it.UpdatedAt); err != nil { + slog.Error("httpapi: knowledge/recent row scan failed", "error", err) continue } it.Source = src