argoproj/argo-workflows · error
unable to retrieve stats for downloaded file %s: %w
Error message
unable to retrieve stats for downloaded file %s: %w
What it means
After DownloadFile succeeds in Load, the driver calls os.Lstat(path) to determine the blob's size (an empty file may represent a downloaded ADLS Gen2 directory); if the stat fails — path missing, permission denied, or filesystem error — this wrapped error is returned.
Source
Thrown at workflow/artifacts/azure/azure.go:131
WithField("blob", artifact.Azure.Blob).
Info(ctx, "Downloading from Azure Blob Storage")
containerClient, err := azblobDriver.newAzureContainerClient(ctx)
if err != nil {
return fmt.Errorf("unable to create Azure Blob Container client: %w", err)
}
// Assume we're not downloading a directory and try to download as a file, since this is
// the most common case and we don't want the penalty of listing the blobs before we
// download (to determine if it's a directory instead of a single file). If we get a
// BlobNotFound error, then check if it's a directory and process accordingly. If the account
// has HNS enabled (ADLS Gen 2), then there's an edge case with using the blob API to
// access. The directory will be returned as an empty file, so check for that as well.
var isEmptyFile bool
origErr := DownloadFile(ctx, containerClient, artifact.Azure.Blob, path)
if origErr == nil {
fileInfo, lstatErr := os.Lstat(path)
if lstatErr != nil {
return fmt.Errorf("unable to retrieve stats for downloaded file %s: %w", path, lstatErr)
}
// Empty file means it could be an ADLS Gen 2 account and we downloaded the
// directory as an empty file -- we'll check below. If it's a non-empty file,
// then we successfully downloaded a file blob.
if fileInfo.Size() > 0 {
return nil
}
isEmptyFile = true
} else if !bloberror.HasCode(origErr, bloberror.BlobNotFound) {
return fmt.Errorf("unable to download blob %s: %w", artifact.Azure.Blob, origErr)
}
isDir, err := azblobDriver.IsDirectory(ctx, artifact)
if err != nil {
return fmt.Errorf("unable to determine if %s is a directory: %w", artifact.Azure.Blob, err)
}
View on GitHub (pinned to 35bff19146)
Solutions
- Inspect the wrapped lstatErr cause to identify ENOENT vs EACCES vs EIO.
- Check the artifact path volume is writable and not concurrently cleaned (no conflicting sidecars/scanners).
- Re-run the workflow — a transient node/filesystem issue often resolves on retry.
- Verify securityContext/fsGroup settings allow the executor user to stat files under /tmp (or the configured artifact path).
Defensive patterns
Strategy: retry
Validate before calling
// ensure the artifact dir is writable before download:
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err }
if f, err := os.CreateTemp(filepath.Dir(path), ".probe"); err == nil { f.Close(); os.Remove(f.Name()) } Try / catch
if err := DownloadFile(ctx, client, blob, path); err == nil {
_, lstatErr := os.Lstat(path)
if lstatErr != nil {
if os.IsNotExist(lstatErr) || os.IsPermission(lstatErr) {
return retryDownload(ctx, client, blob, path) // transient/perm issue
}
return fmt.Errorf("lstat %s: %w", path, lstatErr)
}
} Prevention
- Keep artifact volumes writable and sized adequately; avoid read-only mounts for output paths.
- Don't run sidecars/scanners that clean the artifact directory during execution.
- Set fsGroup/securityContext so the executor user owns downloaded files.
When it happens
Trigger: The downloaded file disappeared between download and stat (race, cleanup), the mount holding the artifact path is read-only or full, or the executor lacks permission to stat the file it just wrote on a volume with restrictive permissions.
Common situations: Running with securityContext that restricts filesystem access on the emptyDir/hostPath artifact volume; node disk pressure; a security scanner or sidecar deleting files in the artifacts directory mid-workflow.
Related errors
- unable to remove attempted file download %s: %w
- failed to stat input artifact %q at %s: %w
- failed to create parent directory for 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/1d058c6e55afe9a6.
Report an issue: GitHub.