From cbd3eb1cd2368b8d0b5c1eecc905cf1e86a3fa22 Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Wed, 9 Jul 2025 15:36:16 -0700 Subject: [PATCH] fix: ListMultipartUploads pagination panic and duplicate results This fixes a panic seen when there were a lot of multipart uploads in the same bucket requiring multiple paginated responses. for example: panic: runtime error: index out of range [11455] with length 1000 goroutine 418 [running]: github.com/versity/versitygw/backend/posix.(*Posix).ListMultipartUploads(0xc0004300 /Users/ben/repo/versitygw/backend/posix/posix.go:2122 +0xd25 github.com/versity/versitygw/s3api/controllers.S3ApiController.ListActions({{0x183c ... This change updates the ListMultipartUploads implementation to properly advance past the (KeyMarker, UploadIDMarker) tuple when paginating, ensuring that each response starts after the marker and does not include duplicate uploads. --- backend/posix/posix.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/backend/posix/posix.go b/backend/posix/posix.go index bb99ebea..a99b7aa4 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -2117,28 +2117,33 @@ func (p *Posix) ListMultipartUploads(_ context.Context, mpu *s3.ListMultipartUpl return uploads[i].Key < uploads[j].Key }) - for i := keyMarkerInd + 1; i < len(uploads); i++ { - if maxUploads == 0 { - break + start := 0 + if keyMarker != "" { + for i, up := range uploads { + if up.Key == keyMarker && (uploadIDMarker == "" || + up.UploadID == uploadIDMarker) { + // Start after the marker + start = i + 1 + break + } } - if keyMarker != "" && uploadIDMarker != "" && uploads[i].UploadID < uploadIDMarker { - continue - } - if i != len(uploads)-1 && len(resultUpds) == maxUploads { + } + + for i := start; i < len(uploads); i++ { + if len(resultUpds) == maxUploads { return s3response.ListMultipartUploadsResult{ Bucket: bucket, Delimiter: delimiter, KeyMarker: keyMarker, MaxUploads: maxUploads, - NextKeyMarker: resultUpds[i-1].Key, - NextUploadIDMarker: resultUpds[i-1].UploadID, + NextKeyMarker: resultUpds[len(resultUpds)-1].Key, + NextUploadIDMarker: resultUpds[len(resultUpds)-1].UploadID, IsTruncated: true, Prefix: prefix, UploadIDMarker: uploadIDMarker, Uploads: resultUpds, }, nil } - resultUpds = append(resultUpds, uploads[i]) }