From bdb07799d37995dd4ae0b4f8ae37e68e62351b17 Mon Sep 17 00:00:00 2001 From: Bradley Erickson Date: Tue, 30 Jun 2026 14:38:03 -0700 Subject: [PATCH] fix(api): return 200 instead of 500 when listing attachments on a task with none ReadAll used a bare return when len(attachments) == 0, which returned nil for the interface{} result. The v2 handler's type assertion then failed on nil, producing an untyped error that Huma surfaced as 500. Return the empty slice explicitly so the assertion succeeds. Co-Authored-By: Claude Opus 4.6 --- pkg/models/task_attachment.go | 2 +- pkg/webtests/huma_task_attachment_test.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pkg/models/task_attachment.go b/pkg/models/task_attachment.go index 327e2311a..94893a061 100644 --- a/pkg/models/task_attachment.go +++ b/pkg/models/task_attachment.go @@ -252,7 +252,7 @@ func (ta *TaskAttachment) ReadAll(s *xorm.Session, a web.Auth, _ string, page in } if len(attachments) == 0 { - return + return attachments, 0, 0, nil } fileIDs := make([]int64, 0, len(attachments)) diff --git a/pkg/webtests/huma_task_attachment_test.go b/pkg/webtests/huma_task_attachment_test.go index 74d4ea0ed..21babfe5f 100644 --- a/pkg/webtests/huma_task_attachment_test.go +++ b/pkg/webtests/huma_task_attachment_test.go @@ -183,6 +183,26 @@ func TestTaskAttachmentsV2(t *testing.T) { assert.Equal(t, http.StatusForbidden, rec.Code, "body: %s", rec.Body.String()) }) + t.Run("List empty returns 200 not 500", func(t *testing.T) { + // Regression: listing attachments on a task with zero attachments + // returned HTTP 500 because ReadAll returned nil instead of an empty slice. + e, err := setupTestEnv() + require.NoError(t, err) + token := humaTokenFor(t, &testuser1) + + // Task 2 exists in project 1 (owned by testuser1) and has no attachment fixtures. + rec := humaRequest(t, e, http.MethodGet, "/api/v2/tasks/2/attachments", "", token, "") + require.Equal(t, http.StatusOK, rec.Code, "body: %s", rec.Body.String()) + + var resp struct { + Items []*models.TaskAttachment `json:"items"` + Total int64 `json:"total"` + } + require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp)) + assert.Empty(t, resp.Items) + assert.Zero(t, resp.Total) + }) + t.Run("List forbidden on inaccessible task", func(t *testing.T) { e, err := setupTestEnv() require.NoError(t, err)