juicedata/juicefs · warning
(cancelled) upload block %s: %s (after %d tries)
Error message
(cancelled) upload block %s: %s (after %d tries)
What it means
Upload retries with quadratic backoff (try*try seconds) up to `max` attempts (3, or MaxRetries+1 for sync writes). If the owning slice signals s.uploadError (the upload was cancelled/superseded) during the retry loop, the loop breaks early and reports "(cancelled) upload block ..." with the last error and try count. The block will be handled by a subsequent upload instead.
Source
Thrown at pkg/chunk/cached_store.go:374
if sync && (blen < store.conf.BlockSize || store.conf.CacheLargeWrite) {
// block will be freed after written into disk
store.bcache.cache(key, block, false, false)
}
n, err := store.compressor.Compress(buf.Data, block.Data)
block.Release()
if err != nil {
return fmt.Errorf("Compress block key %s: %s", key, err)
}
buf.Data = buf.Data[:n]
try, max := 0, 3
if sync {
max = store.conf.MaxRetries + 1
}
for ; try < max; try++ {
time.Sleep(time.Second * time.Duration(try*try))
if s != nil && s.uploadError != nil {
err = fmt.Errorf("(cancelled) upload block %s: %s (after %d tries)", key, err, try)
break
}
if err = store.put(ctx, key, buf); err == nil {
break
}
logger.Debugf("Upload %s: %s (try %d)", key, err, try+1)
}
if err != nil && try >= max {
err = fmt.Errorf("(max tries) upload block %s: %s (after %d tries)", key, err, try)
}
return err
}
func (s *wSlice) upload(indx int) {
blen := s.blockSize(indx)
key := s.key(indx)
pages := s.pages[indx]
s.pages[indx] = nilView on GitHub (pinned to c9a67b23e8)
Solutions
- Inspect the wrapped inner error (%s) and try count to see why the upload failed or was cancelled.
- Check object storage connectivity/credentials (S3 endpoint reachability, keys, clocks) if the cause is repeated put() failure.
- Keep the client mounted until uploads drain (avoid unmount/kill during heavy writes); enable --writeback with sufficient retention.
- Increase --max-uploads/retry budget for large or slow uploads and ensure network stability; re-mount to let pending blocks re-upload.
Example fix
// before (client killed during writeback, blocks lost from retry window) kill <juicefs-pid> // after (graceful drain) umount /mnt/jfs # lets pending uploads finish/flush before process exit
Defensive patterns
Strategy: retry
Validate before calling
// verify object storage reachability before heavy writes
resp, err := http.Head(os.Getenv("JFS_MINIO") + "/minio/health/ready") Try / catch
if err != nil && strings.Contains(err.Error(), "(cancelled) upload block") {
// re-mount or wait; pending blocks are re-uploaded on next pass
} Prevention
- Avoid unmounting/killing clients while uploads are in flight
- Set adequate retry/timeout budgets for slow object storage
- Alert on object storage 5xx/latency so outages are caught early
When it happens
Trigger: While sleeping/backing off between put() retries, another goroutine sets s.uploadError (slice closed, aborted, or a newer state superseded this upload); also occurs when put() repeatedly fails and the slice is aborted mid-retry — often due to unmount, context cancellation, or network outage lasting past the retry window.
Common situations: Unmounting or killing a client while uploads are in flight; object storage outages (S3 timeouts, 5xx) exhausting retries; writeback mode where the process exits before pending uploads complete.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- (max tries) upload block %s: %s (after %d tries)
- bad response status %s
- begin upload %s: %w
- ceph: can't put empty file
- are you connected to the network?
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/09a68000395cb2c6.
Report an issue: GitHub.