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)