argoproj/argo-workflows · error
unable to test if blob %s is a directory: %w
Error message
unable to test if blob %s is a directory: %w
What it means
After OpenStream hits BlobNotFound or an empty file, it calls IsDirectory to check whether the blob name is actually a directory (prefix). If IsDirectory itself fails (listing the prefix errors), the driver wraps that failure with this message instead of deciding file-vs-directory.
Source
Thrown at workflow/artifacts/azure/azure.go:261
// Attempt the download. If it fails with a BlobNotFound error, or succeeds but with
// a content length of 0, then it could be that we're attempting to stream a directory.
// Check if the blob represents a directory and return an error if so. If not, then
// return either the original BlobNotFound error or the empty file stream.
emptyFile := false
response, origErr := blobClient.DownloadStream(ctx, nil)
if origErr == nil {
emptyFile = *response.ContentLength == 0
// We have a normal file blob, so just return the response body stream
if !emptyFile {
return response.Body, nil
}
} else if !bloberror.HasCode(origErr, bloberror.BlobNotFound) {
return nil, fmt.Errorf("unable to open stream for blob %s: %w", artifact.Azure.Blob, origErr)
}
isDir, err := azblobDriver.IsDirectory(ctx, artifact)
if err != nil {
return nil, fmt.Errorf("unable to test if blob %s is a directory: %w", artifact.Azure.Blob, err)
}
if isDir {
return nil, argoerrors.New(argoerrors.CodeNotImplemented, "Directory Stream capability currently unimplemented for Azure Blob")
} else if !emptyFile {
// Not a directory (and not successful retrieval of an empty file), so return
// the original BlobNotFound error
return nil, fmt.Errorf("unable to open blob stream for %s: %w", artifact.Azure.Blob, origErr)
}
return response.Body, nil
}
// Save saves an artifact to Azure Blob Storage
func (azblobDriver *ArtifactDriver) Save(ctx context.Context, path string, outputArtifact *wfv1.Artifact) error {
logger := logging.RequireLoggerFromContext(ctx)
logger.WithField("endpoint", outputArtifact.Azure.Endpoint).
WithField("container", outputArtifact.Azure.Container).
WithField("blob", outputArtifact.Azure.Blob).View on GitHub (pinned to 35bff19146)
Solutions
- Fix the cause of the listing failure shown by the wrapped error (credentials, container existence, permissions).
- Ensure the account key/identity has Storage Blob Data Reader (list) rights, not just read of a single blob.
- Verify container name and endpoint in the artifact spec.
- Retry on transient storage errors.
- If the artifact should really exist, check the producing step's blob name matches exactly (no stray prefix).
Example fix
// before: identity lacks list permission role: "Storage Blob Data Reader (read only single blob)" // after: grant data-plane list access role: "Storage Blob Data Reader" # includes list on container
Defensive patterns
Strategy: retry
Validate before calling
props, err := containerClient.NewBlockBlobClient(blob).GetProperties(ctx, nil)
if err != nil && !bloberror.HasCode(err, bloberror.BlobNotFound) {
return fmt.Errorf("storage backend unhealthy: %w", err)
} Type guard
func isTransientAzureErr(err error) bool {
var re *azcore.ResponseError
return errors.As(err, &re) && (re.StatusCode == 429 || re.StatusCode >= 500)
} Try / catch
err := driver.OpenStream(ctx, artifact)
// wrap call
if err != nil && strings.Contains(err.Error(), "unable to test if blob") {
if isTransientAzureErr(errors.Unwrap(err)) {
// exponential backoff retry
}
} Prevention
- Grant the storage identity data-plane LIST rights (Storage Blob Data Reader+).
- Retry transient 429/5xx storage errors with backoff.
- Check container existence before artifact reads.
When it happens
Trigger: OpenStream on a missing/empty blob when the subsequent ListBlob flat-metadata call inside IsDirectory fails: auth errors, container not found, throttling, network failures.
Common situations: Same credential problems as the original download but only surfacing on the fallback path; ADLS Gen2 accounts where prefix listing needs extra permissions; transient 429/503 during listing.
Related errors
- unable to determine if %s is a directory: %w
- unable to list blob %s in Azure Storage: %w
- unable to open stream for blob %s: %w
- unable to open blob stream for %s: %w
- unable to upload directory %s to Azure: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/1b34938013352132.
Report an issue: GitHub.