Skip to content

Commit b847e64

Browse files
wesmclaude
andcommitted
Fix app freeze on empty search results
The search API returned JSON `null` instead of `[]` when no results matched, because Go's nil slice serializes as null. The frontend then crashed on `null.length`, breaking the Escape handler and freezing the command palette. Fix: ensure the server handler always returns an empty array. Add a frontend null-coalesce guard as defense in depth. Fixes #34 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9a08bf6 commit b847e64

3 files changed

Lines changed: 27 additions & 3 deletions

File tree

frontend/src/lib/stores/search.svelte.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class SearchStore {
5656
{ project: project || undefined, limit: 30 },
5757
{ signal },
5858
);
59-
this.results = res.results;
59+
this.results = res.results ?? [];
6060
} catch (error: unknown) {
6161
if (error instanceof DOMException
6262
&& error.name === "AbortError") {

internal/server/search.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,14 @@ func (s *Server) handleSearch(
6868
return
6969
}
7070

71+
results := page.Results
72+
if results == nil {
73+
results = []db.SearchResult{}
74+
}
7175
writeJSON(w, http.StatusOK, searchResponse{
7276
Query: query,
73-
Results: page.Results,
74-
Count: len(page.Results),
77+
Results: results,
78+
Count: len(results),
7579
Next: page.NextCursor,
7680
})
7781
}

internal/server/server_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,26 @@ func TestSearch_DeadlineExceeded(t *testing.T) {
894894
assertTimeoutRace(t, w)
895895
}
896896

897+
func TestSearch_ZeroResults(t *testing.T) {
898+
te := setup(t)
899+
if !te.db.HasFTS() {
900+
t.Skip("skipping search test: no FTS support")
901+
}
902+
te.seedSession(t, "s1", "my-app", 1)
903+
te.seedMessages(t, "s1", 1)
904+
905+
w := te.get(t, "/api/v1/search?q=spamalot")
906+
assertStatus(t, w, http.StatusOK)
907+
908+
resp := decode[searchResponse](t, w)
909+
if resp.Results == nil {
910+
t.Fatal("results must be [] not null")
911+
}
912+
if resp.Count != 0 {
913+
t.Fatalf("expected count=0, got %d", resp.Count)
914+
}
915+
}
916+
897917
func TestSearch_NotAvailable(t *testing.T) {
898918
te := setup(t)
899919
// Simulate missing FTS by dropping the virtual table.

0 commit comments

Comments
 (0)