argoproj/argo-workflows · error
unable to create local directory %s: %w
Error message
unable to create local directory %s: %w
What it means
After successfully listing the directory's blobs, DownloadDirectory creates the local destination directory with os.MkdirAll(path, 0755) before writing children. This error means creating that local directory failed — a purely local filesystem problem.
Source
Thrown at workflow/artifacts/azure/azure.go:209
return err
}
// DownloadDirectory downloads all of the files starting with the named blob prefix into a local directory.
func (azblobDriver *ArtifactDriver) DownloadDirectory(ctx context.Context, containerClient *container.Client, artifact *wfv1.Artifact, path string) error {
logger := logging.RequireLoggerFromContext(ctx)
logger.WithField("endpoint", artifact.Azure.Endpoint).
WithField("container", artifact.Azure.Container).
WithField("blob", artifact.Azure.Blob).
Info(ctx, "Downloading directory from Azure Blob Storage")
files, err := azblobDriver.ListObjects(ctx, artifact)
if err != nil {
return fmt.Errorf("unable to list blob %s in Azure Storage: %w", artifact.Azure.Blob, err)
}
err = os.MkdirAll(path, 0755)
if err != nil {
return fmt.Errorf("unable to create local directory %s: %w", path, err)
}
for _, file := range files {
// For ADLS Gen 2 accounts, we'll see a file whose name matches the directory. Skip it.
if file == artifact.Azure.Blob {
continue
}
relKeyPath := strings.TrimPrefix(file, artifact.Azure.Blob)
localPath := filepath.Join(path, relKeyPath)
err = DownloadFile(ctx, containerClient, file, localPath)
if err != nil {
return fmt.Errorf("unable to download file %s: %w", localPath, err)
}
}
return nil
}View on GitHub (pinned to 35bff19146)
Solutions
- Ensure the artifact `path` is a clean writable directory location (does not exist as a file).
- Fix volume permissions so the executor user can create the directory (securityContext fsGroup/runAsUser).
- Check the wrapped syscall: EACCES => permissions, EROFS => read-only mount, ENAMETOOLONG => shorter prefix.
- Pre-create the target directory in the image or a prior step.
- Point directory artifacts at an emptyDir or dedicated PVC path.
Example fix
// before: path exists as file path: /mnt/data # regular file // after path: /mnt/data/dir
Defensive patterns
Strategy: validation
Validate before calling
st, err := os.Lstat(path)
if err == nil && !st.IsDir() {
return fmt.Errorf("%s exists as a file; choose a directory path", path)
}
if err := os.MkdirAll(path, 0o755); err != nil { return err } Type guard
func canCreateDir(p string) error {
if fi, err := os.Lstat(p); err == nil && !fi.IsDir() {
return fmt.Errorf("file blocks dir %s", p)
}
return nil
} Prevention
- Point directory artifacts at dedicated empty paths
- Set securityContext fsGroup so the executor can write to volumes
- Avoid read-only mounts as artifact destinations
- Keep blob prefixes short to limit local path length
When it happens
Trigger: os.MkdirAll(path) fails: an existing regular file occupies `path` (ENOTDIR/EEXIST semantics via intermediate), read-only volume, permission denied for the executor user, or ENOSPC/ENAMETOOLONG.
Common situations: Directory artifact path already exists as a file in the container, artifact path is on a read-only configMap/config mount, non-root executor cannot write to the given volume, deep blob prefixes making the local path too long.
Related errors
- mkdir %s error: %w
- failed to create folder path: %w
- failed to write large arg %d to file: %w
- failed to leave working directory before staging input artif
- failed to create parent directory for artifact %q at %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/97cd022a586478cc.
Report an issue: GitHub.