argoproj/argo-workflows · error
unable to create dir for file %s: %w
Error message
unable to create dir for file %s: %w
What it means
DownloadFile first ensures the parent directory of the destination path exists via os.MkdirAll before creating the file. This error means that MkdirAll failed, so the local filesystem could not be prepared for the blob download. It is a local FS error, not an Azure error.
Source
Thrown at workflow/artifacts/azure/azure.go:177
return fmt.Errorf("unable to remove attempted file download %s: %w", path, err)
}
// It's a directory, so download all of the files.
err = azblobDriver.DownloadDirectory(ctx, containerClient, artifact, path)
if err != nil {
return fmt.Errorf("unable to download directory %s: %w", artifact.Azure.Blob, err)
}
return nil
}
// DownloadFile downloads a single file from Azure Blob Storage
func DownloadFile(ctx context.Context, containerClient *container.Client, blobName, path string) error {
blobClient := containerClient.NewBlobClient(blobName)
err := os.MkdirAll(filepath.Dir(path), 0755)
if err != nil {
return fmt.Errorf("unable to create dir for file %s: %w", path, err)
}
outFile, err := os.Create(path)
if err != nil {
return fmt.Errorf("unable to create file %s: %w", path, err)
}
defer func() {
if closeErr := outFile.Close(); closeErr != nil {
logger := logging.RequireLoggerFromContext(ctx)
logger.WithFatal().WithError(closeErr).Warn(ctx, "unable to close file")
}
}()
_, err = blobClient.DownloadFile(ctx, outFile, nil)
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 {View on GitHub (pinned to 35bff19146)
Solutions
- Fix the artifact `path` so its parent is a writable directory and no file occupies an intermediate component.
- Ensure the volume is mounted at the path and is writable by the executor user.
- Check the wrapped syscall in the message: ENOTDIR => a file blocks a dir component; EACCES => permissions; EROFS => read-only mount.
- Pre-create the destination directory in the step's container image/entrypoint if needed.
- For directory artifacts, use a clean empty target directory.
Example fix
// before: path parent is a file path: /tmp/out/data/result.txt # /tmp/out/data is a regular file // after: correct path path: /tmp/artifacts/result.txt
Defensive patterns
Strategy: validation
Validate before calling
parent := filepath.Dir(path)
st, err := os.Stat(parent)
if err == nil && !st.IsDir() {
return fmt.Errorf("%s exists and is not a directory", parent)
}
// verify write access
if f, err := os.CreateTemp(parent, ".probe"); err != nil { return err } else { f.Close(); os.Remove(f.Name()) } Type guard
func ensureWritableDir(p string) error {
if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
return fmt.Errorf("file blocks directory %s", p)
}
return os.MkdirAll(p, 0o755)
} Prevention
- Choose artifact paths whose parent is a clean writable directory
- Avoid nested artifact paths that can collide with saved files
- Mount a dedicated emptyDir/PVC for artifacts
- Pre-create output directories in the container image
When it happens
Trigger: os.MkdirAll(filepath.Dir(path)) fails: parent path component is an existing regular file (ENOTDIR), read-only filesystem (EROFS), permission denied (EACCES), or path is empty/invalid on the target volume.
Common situations: Artifact path points inside a location already occupied by a file, emptyDir not mounted at the configured path, executor user lacks write access to the mount, downloading into a nested path where a file exists with the same name as an intermediate directory (common with directory artifacts).
Related errors
- unable to create file %s: %w
- unable to create local directory %s: %w
- mkdir %s: %w
- mkdir %s error: %w
- failed to create folder path: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/750b2e99976f02cf.
Report an issue: GitHub.