argoproj/argo-workflows · error
failed to clear existing path for artifact %q at %s: %w
Error message
failed to clear existing path for artifact %q at %s: %w
What it means
After the volume-safety checks pass, argoexec removes whatever already exists at the artifact destination (os.RemoveAll) so the symlink can be placed. If that removal fails (permissions, read-only filesystem, EBUSY), the error is wrapped with this message and the step fails.
Source
Thrown at cmd/argoexec/commands/emissary.go:434
// (resolve the parent, not the final element, so an image symlink *at*
// art.Path is just unlinked rather than followed). If that resolved
// path overlaps a user-declared volume, clearing it would recurse into
// and destroy a live PVC/hostPath/emptyDir, so refuse. Benign system
// mounts (tmpfs /run, the overlay rootfs) are not declared user volumes
// and so remain safe to shadow.
realParent, evalErr := filepath.EvalSymlinks(filepath.Dir(dst))
if evalErr != nil {
return fmt.Errorf("failed to resolve parent of artifact path %q at %s: %w", art.Name, dst, evalErr)
}
resolved := filepath.Join(realParent, filepath.Base(dst))
if mnt := common.FindOverlappingVolume(tmpl, resolved); mnt != nil {
return fmt.Errorf("refusing to stage input artifact %q at %s: it resolves to %s inside volume mount %q (%s), and clearing it would destroy the mounted volume; change the artifact path or volume mount so they do not overlap", art.Name, dst, resolved, mnt.Name, mnt.MountPath)
}
if mnt := common.FindVolumeMountNestedUnderPath(tmpl, resolved); mnt != nil {
return fmt.Errorf("refusing to stage input artifact %q at %s: it resolves to %s which contains volume mount %q (%s), and clearing it would destroy the mounted volume; change the artifact path or volume mount so they do not overlap", art.Name, dst, resolved, mnt.Name, mnt.MountPath)
}
if rmErr := os.RemoveAll(dst); rmErr != nil {
return fmt.Errorf("failed to clear existing path for artifact %q at %s: %w", art.Name, dst, rmErr)
}
}
if err := os.Symlink(src, dst); err != nil {
return fmt.Errorf("failed to symlink input artifact %q (%s -> %s): %w", art.Name, dst, src, err)
}
logger.WithFields(logging.Fields{"name": art.Name, "src": src, "dst": dst}).Debug(ctx, "linked input artifact")
}
return nil
}
// waitForSupervisorReady blocks until the supervisor's status marker reports a
// terminal outcome (READY/FAILED), or until the supervisor is presumed dead.
// Used only in init-less pod mode where main and supervisor start concurrently.
// VarRunArgoPath itself is guaranteed to exist because the emissary has
// already created /var/run/argo/ctr/<name> earlier in main, which MkdirAll'd
// the full parent chain.
func waitForSupervisorReady(ctx context.Context) error {
return waitForSupervisorReadyAt(ctx, common.StatusMarkerPath, supervisorHeartbeatTimeout, supervisorStatusPollInterval)View on GitHub (pinned to 35bff19146)
Solutions
- Make the destination path writable by the container user (chown/chmod in the image, or run with an appropriate securityContext fsGroup)
- Choose a destination on a writable filesystem (emptyDir volume, /tmp)
- If the path is a mount point, change the artifact path so it is not exactly at a mountPath
- Ensure the container filesystem is not mounted readOnly for the directory containing the path
Example fix
# before
securityContext:
runAsUser: 1000
inputs:
artifacts:
- name: cfg
path: /etc/app/config.yaml # root-owned, non-root cannot clear
# after
inputs:
artifacts:
- name: cfg
path: /tmp/app/config.yaml Defensive patterns
Strategy: validation
Validate before calling
// In the image build, pre-create and chown the artifact destination directory: # Dockerfile RUN mkdir -p /etc/app && chown 1000:1000 /etc/app # Or choose a path on an emptyDir volume, which is always writable by the container user.
Prevention
- Pre-create artifact destination directories in the image with correct ownership
- Run containers with securityContext.fsGroup matching the volume GID
- Avoid read-only root filesystems when using artifact paths on /
- Never place artifact paths exactly at mountPath locations
When it happens
Trigger: os.RemoveAll(dst) returns an error while staging input artifacts: destination is on a read-only filesystem, owned by another user, a non-empty mount point, or otherwise undeletable.
Common situations: Artifact path on a read-only rootfs or read-only PVC; destination is an active mount point (busy); container runs as non-root but path is owned by root; image sets immutable attributes.
Related errors
- failed to create parent directory for artifact %q at %s: %w
- failed to leave working directory before staging input artif
- failed to stat input artifact %q at %s: %w
- failed to stat artifact path %q at %s: %w
- failed to resolve parent of artifact path %q at %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/2d31a24d849da5f3.
Report an issue: GitHub.