docker/compose · error

deleting paths in %s: %w

Error message

deleting paths in %s: %w

What it means

During Tar.Sync, when some host paths no longer exist, compose builds an 'rm -rf <paths>' command and execs it in each matching container via LowLevelClient.Exec before copying. If that exec fails for a container (non-zero exit, exec API failure, container restarting/paused), the error is collected (not fail-fast) and joined into the sync result. The %s names the offending container ID.

Source

Thrown at internal/sync/tar.go:105

		deleteCmd = append([]string{"rm", "-rf"}, pathsToDelete...)
	}

	var (
		eg    errgroup.Group
		errMu sync.Mutex
		errs  = make([]error, 0, len(containers)*2) // max 2 errs per container
	)

	eg.SetLimit(16) // arbitrary limit, adjust to taste :D
	for i := range containers {
		containerID := containers[i].ID
		tarReader := tarArchive(pathsToCopy)

		eg.Go(func() error {
			if len(deleteCmd) != 0 {
				if err := t.client.Exec(ctx, containerID, deleteCmd, nil); err != nil {
					errMu.Lock()
					errs = append(errs, fmt.Errorf("deleting paths in %s: %w", containerID, err))
					errMu.Unlock()
				}
			}

			if err := t.client.Untar(ctx, containerID, tarReader); err != nil {
				errMu.Lock()
				errs = append(errs, fmt.Errorf("copying files to %s: %w", containerID, err))
				errMu.Unlock()
			}
			return nil // don't fail-fast; collect all errors
		})
	}

	_ = eg.Wait()
	return errors.Join(errs...)
}

type ArchiveBuilder struct {

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. docker inspect <containerID> to check State (Paused/Restarting) and unpause or wait for it: docker unpause <id> or docker compose restart <service>
  2. If the image is distroless/scratch, add rm (busybox) or avoid deletions in sync paths since exec rm -rf cannot work there
  3. Check dockerd logs for exec API errors; restart the container if its exec channel is wedged
  4. If deletions are not needed, ensure host paths in the mapping still exist so deleteCmd stays empty
Defensive patterns

Strategy: try-catch

Validate before calling

// only pass delete-mappings when containers can exec rm
if len(deletedPaths) > 0 {
    for _, c := range containers {
        st, _ := client.ContainerInspect(ctx, c.ID)
        if st.State == nil || st.State.Paused || st.State.Restarting { skipOrWait(c.ID) }
    }
}

Try / catch

// Sync joins per-container errors; split with errors.Unwrap on the joined tree and match the 'deleting paths in <id>' prefix to target one container
for _, e := range errors.Unwrap(syncErr).([]error) { /* handle per container ID */ }

Prevention

When it happens

Trigger: Tar.Sync with at least one deleted host path (len(pathsToDelete) != 0) against a container that cannot run exec: container is paused, restarting, its runtime exec API errors, or 'rm' is absent/not executable in the image (distroless/scratch).

Common situations: Syncing deletions to minimal images without coreutils, containers mid-restart during 'docker compose watch', or a stopped-but-listed replica whose exec channel is closed.

Related errors


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/5c44bc8cec11e768. Report an issue: GitHub.