argoproj/argo-workflows · error
unable to create file %s: %w
Error message
unable to create file %s: %w
What it means
DownloadFile creates (or truncates) the local destination file with os.Create before streaming the blob into it. This error means os.Create failed, so nothing was downloaded. Typical causes are local filesystem problems at the exact destination path, not Azure-side issues.
Source
Thrown at workflow/artifacts/azure/azure.go:181
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 {
logger := logging.RequireLoggerFromContext(ctx)
logger.WithField("endpoint", artifact.Azure.Endpoint).
WithField("container", artifact.Azure.Container).
WithField("blob", artifact.Azure.Blob).View on GitHub (pinned to 35bff19146)
Solutions
- Check the wrapped syscall: EACCES => fix permissions/securityContext; EISDIR => choose a file path; ENOSPC => free disk or expand the volume.
- Ensure the artifact path points to a file location writable by argoexec, not a directory.
- Free up disk on the node/emptyDir if ENOSPC.
- Shorten blob names/prefixes for directory artifacts if ENAMETOOLONG.
- Verify the mount backing the path is rw (kubectl describe pod mounts).
Example fix
// before: path is a directory path: /mnt/out // after path: /mnt/out/data.txt
Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(path); err == nil && fi.IsDir() {
return fmt.Errorf("%s is a directory, expected a file path", path)
}
if err := unix.Access(filepath.Dir(path), unix.W_OK); err != nil {
return fmt.Errorf("no write access to %s", filepath.Dir(path))
} Type guard
func canCreateFile(p string) error {
if fi, err := os.Stat(p); err == nil && fi.IsDir() {
return fmt.Errorf("%s is a directory", p)
}
f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil { return err }
return f.Close()
} Prevention
- Ensure artifact path targets a file, not an existing directory
- Size emptyDir volumes for expected artifact sizes to avoid ENOSPC
- Match executor securityContext to volume ownership (fsGroup)
- Keep blob-derived paths short to avoid ENAMETOOLONG
When it happens
Trigger: os.Create(path) fails with EACCES (no write permission), EISDIR (path is an existing directory), ENOSPC (disk full), ENAMETOOLONG, or the volume is read-only.
Common situations: Artifact destination path collides with an existing directory, container disk quota/full ephemeral storage, executor running as non-root against root-owned mount, overly long path from deep blob-name prefixes in directory artifacts.
Related errors
- 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
- failed to clear existing path for artifact %q at %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/10ab6d2d6f1a5120.
Report an issue: GitHub.