juicedata/juicefs · error

failed to unmarshal checkpoint: %w

Error message

failed to unmarshal checkpoint: %w

What it means

Load() unmarshals the checkpoint bytes into the Checkpoint struct with encoding/json. This error wraps json.Unmarshal failures, meaning the checkpoint object was read but its content is not valid JSON or does not match the Checkpoint schema (e.g. wrong format, corrupted, or written by an incompatible version). Load treats the checkpoint as unusable and returns without setting m.checkpoint.

Source

Thrown at pkg/sync/checkpoint.go:257

	go m.cleanupCheckpointTmp()
	obj, err := m.dst.Get(ctx, m.checkpointKey, 0, -1)
	if err != nil {
		// head to wrap 404 as os.ErrNotExist
		if _, err := m.dst.Head(ctx, m.checkpointKey); os.IsNotExist(err) {
			return nil, err
		}
		return nil, err
	}
	defer obj.Close()

	data, err := io.ReadAll(obj)
	if err != nil {
		return nil, fmt.Errorf("failed to read checkpoint: %w", err)
	}

	var ckpt Checkpoint
	if err := json.Unmarshal(data, &ckpt); err != nil {
		return nil, fmt.Errorf("failed to unmarshal checkpoint: %w", err)
	}
	if ckpt.MultipartUploads == nil {
		ckpt.MultipartUploads = make(map[string]*multipartUploadState)
	}

	m.checkpoint = &ckpt
	m.multipartUploadStore.reset(ckpt.MultipartUploads)
	return &ckpt, nil
}

// Save saves checkpoint to object storage
func (m *CheckpointManager) Save(ckpt *Checkpoint) error {
	if ckpt.Config != nil && ckpt.Config.Dry {
		return nil
	}
	m.saveMu.Lock()
	defer m.saveMu.Unlock()
	if m.statsUpdater != nil {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Delete/overwrite the stale checkpoint object so Sync starts fresh (or use the force-reset behavior to ignore the existing checkpoint)
  2. Confirm the checkpoint was written by a compatible JuiceFS version; align client versions across workers
  3. Inspect the object content at the checkpoint key to confirm it is valid JSON matching the Checkpoint schema
Defensive patterns

Strategy: validation

Validate before calling

// Validate checkpoint JSON before handing it to Load-equivalent logic
data, _ := io.ReadAll(obj)
if !json.Valid(data) {
	// invalid checkpoint: delete it or force a fresh start
}

Try / catch

ckpt, err := mgr.Load(ctx)
if err != nil {
	if strings.Contains(err.Error(), "failed to unmarshal checkpoint") {
		logger.Warnf("ignoring incompatible/corrupt checkpoint: %v", err)
		ckpt = nil
	}
}

Prevention

When it happens

Trigger: Sync resumes and Load reads the object at m.checkpointKey, but json.Unmarshal fails because the object content is not a valid Checkpoint JSON document — file written by a different tool/format, schema drift between JuiceFS versions, or truncated/partial JSON from an interrupted Save.

Common situations: Upgrading JuiceFS between versions where Checkpoint fields changed; checkpoint object corrupted in the object store; user accidentally pointed the sync at an object that isn't a checkpoint; interrupted previous run left partial data.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/40e9e3500c6f0d12. Report an issue: GitHub.