protondrive: fix long hangs on permanent validation failures

shouldRetry treated every Code=200501 API error as a transient storage
block error and retried it. Proton also returns Code=200501 with an
HTTP 422 for permanent validation failures (e.g. a content key packet
that cannot be verified, or an upload format the account is not
enabled for), so these were retried until the operation timed out
causing a multi-minute hang.

This fixes it by only retrying Code=200501 when it is not a permanent
client (4xx) error.
This commit is contained in:
Nick Craig-Wood
2026-07-13 15:22:47 +01:00
parent bb17d07eb7
commit 4235aa4fe5
2 changed files with 10 additions and 4 deletions
+8 -3
View File
@@ -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.
@@ -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},