From 784312f90e331d1d39d0fb601736457896b05e79 Mon Sep 17 00:00:00 2001 From: bujjibabukatta Date: Fri, 26 Jun 2026 18:03:20 +0530 Subject: [PATCH] fix(azuredevops): treat 204 No Content as graceful skip in timeline collector --- backend/plugins/azuredevops_go/tasks/shared.go | 7 +++++-- backend/plugins/azuredevops_go/tasks/shared_test.go | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/plugins/azuredevops_go/tasks/shared.go b/backend/plugins/azuredevops_go/tasks/shared.go index e6fe0eca1e2..318850077e8 100644 --- a/backend/plugins/azuredevops_go/tasks/shared.go +++ b/backend/plugins/azuredevops_go/tasks/shared.go @@ -153,8 +153,11 @@ func change203To401(res *http.Response) errors.Error { // that failed due to a YAML syntax error never produce a usable timeline), instead // of aborting the entire subtask. func ignoreInvalidTimelineResponse(res *http.Response) errors.Error { - // Keep existing behaviour: treat 404 as a graceful skip (build was deleted). - if res.StatusCode == http.StatusNotFound { + // Treat 404 (build deleted) and 204 (build has no timeline data) as + // graceful skips so the subtask continues instead of failing. + // The 204 guard must come before the body is read because a 204 response + // has an empty body by definition and would cause the JSON parser to fail. + if res.StatusCode == http.StatusNotFound || res.StatusCode == http.StatusNoContent { return api.ErrIgnoreAndContinue } diff --git a/backend/plugins/azuredevops_go/tasks/shared_test.go b/backend/plugins/azuredevops_go/tasks/shared_test.go index 353ae3f4c91..d46e01d6c0d 100644 --- a/backend/plugins/azuredevops_go/tasks/shared_test.go +++ b/backend/plugins/azuredevops_go/tasks/shared_test.go @@ -41,6 +41,12 @@ func TestIgnoreInvalidTimelineResponse_404(t *testing.T) { assert.Equal(t, api.ErrIgnoreAndContinue, err, "404 should return ErrIgnoreAndContinue") } +func TestIgnoreInvalidTimelineResponse_204(t *testing.T) { + res := makeResponse(http.StatusNoContent, "") + err := ignoreInvalidTimelineResponse(res) + assert.Equal(t, api.ErrIgnoreAndContinue, err, "204 No Content should return ErrIgnoreAndContinue") +} + func TestIgnoreInvalidTimelineResponse_EmptyBody(t *testing.T) { res := makeResponse(http.StatusOK, "") err := ignoreInvalidTimelineResponse(res)