diff --git a/backend/protondrive/protondrive.go b/backend/protondrive/protondrive.go index 9188383cf..4595ea5dc 100644 --- a/backend/protondrive/protondrive.go +++ b/backend/protondrive/protondrive.go @@ -264,9 +264,14 @@ func shouldRetry(ctx context.Context, err error) (bool, error) { } var apiErr *proton.APIError if errors.As(err, &apiErr) { - // Transient storage block error ("Please retry"). - if apiErr.Code == 200501 { - fs.Debugf(nil, "Retrying storage block error: %v", err) + // Code 200501 is a generic Drive operation-failure code. Proton also + // returns it with an HTTP 422 for permanent validation failures (for + // example a content key packet that cannot be verified, or an upload + // format the account is not enabled for), which must NOT be retried - + // doing so spins the pacer until the operation times out. Only retry it + // when it is not a permanent client (4xx) error. + if apiErr.Code == 200501 && (apiErr.Status < 400 || apiErr.Status >= 500) { + fs.Debugf(nil, "Retrying transient storage block error: %v", err) return true, err } // Server errors. 503 is already handled by the SDK; retry the rest. diff --git a/backend/protondrive/protondrive_internal_test.go b/backend/protondrive/protondrive_internal_test.go index aaf2945ae..d1ef4224d 100644 --- a/backend/protondrive/protondrive_internal_test.go +++ b/backend/protondrive/protondrive_internal_test.go @@ -77,7 +77,8 @@ func TestShouldRetry(t *testing.T) { }{ {"nil error", ctx, nil, false}, {"cancelled context", cancelledCtx, errors.New("some error"), false}, - {"storage block error Code=200501", ctx, apiErr(422, 200501), true}, + {"permanent validation error Code=200501 Status=422 (not retried)", ctx, apiErr(422, 200501), false}, + {"transient storage block error Code=200501 Status=500 (retried)", ctx, apiErr(500, 200501), true}, {"server error Status=500", ctx, apiErr(500, 0), true}, {"server error Status=502", ctx, apiErr(502, 0), true}, {"server error Status=504", ctx, apiErr(504, 0), true},