argoproj/argo-workflows · error
failed to test if %s is a directory: %w
Error message
failed to test if %s is a directory: %w
What it means
During artifact download, if GetFile returned NoSuchKey, the driver checks whether the S3 key is actually a 'directory' (prefix). This error wraps a failure of that IsDirectory check itself — the driver could not determine the key's nature, so the download cannot proceed or be classified as not-found.
Source
Thrown at workflow/artifacts/s3/s3.go:219
return err
}
// loadS3Artifact downloads artifacts from an S3 compliant storage
// returns true if the download is completed or can't be retried (non-transient error)
// returns false if it can be retried (transient error)
func loadS3Artifact(ctx context.Context, s3cli Client, inputArtifact *wfv1.Artifact, path string) (bool, error) {
origErr := s3cli.GetFile(inputArtifact.S3.Bucket, inputArtifact.S3.Key, path)
if origErr == nil {
return true, nil
}
if !IsS3ErrCode(origErr, "NoSuchKey") {
return !isTransientS3Err(ctx, origErr), fmt.Errorf("failed to get file: %w", origErr)
}
// If we get here, the error was a NoSuchKey. The key might be an s3 "directory"
isDir, err := s3cli.IsDirectory(inputArtifact.S3.Bucket, inputArtifact.S3.Key)
if err != nil {
return !isTransientS3Err(ctx, err), fmt.Errorf("failed to test if %s is a directory: %w", inputArtifact.S3.Key, err)
}
if !isDir {
// It's neither a file, nor a directory. Return the original NoSuchKey error
return true, argoerrs.New(argoerrs.CodeNotFound, origErr.Error())
}
if err = s3cli.GetDirectory(inputArtifact.S3.Bucket, inputArtifact.S3.Key, path); err != nil {
return !isTransientS3Err(ctx, err), fmt.Errorf("failed to get directory: %w", err)
}
return true, nil
}
// OpenStream opens a stream reader for an artifact from S3 compliant storage
func (s3Driver *ArtifactDriver) OpenStream(ctx context.Context, inputArtifact *wfv1.Artifact) (io.ReadCloser, error) {
log := logging.RequireLoggerFromContext(ctx)
log.WithField("key", inputArtifact.S3.Key).Info(ctx, "S3 OpenStream")
//nolint:contextcheck
s3cli, err := s3Driver.newClient(log.NewBackgroundContext())View on GitHub (pinned to 35bff19146)
Solutions
- Grant the artifact IAM role s3:ListBucket on the bucket so IsDirectory can list the key prefix
- Check bucket/endpoint config (endpoint, region, insecure) in the artifact repository config and retry
- If transient (throttle/network), let the executor retry — the driver already marks transient errors retryable
- Verify credentials (accessKey/secretKey or workload identity) are valid and not expired
Example fix
// before: IAM policy with only GetObject
{"Action": ["s3:GetObject"], "Resource": ["arn:aws:s3:::my-bucket/*"]}
// after: add ListBucket on the bucket
{"Action": ["s3:GetObject", "s3:ListBucket"], "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"]} Defensive patterns
Strategy: validation
Validate before calling
// Check ListBucket access before submitting workflows that load S3 artifacts aws s3api list-objects-v2 --bucket my-bucket --prefix my/key/ --max-items 1 || echo "grant s3:ListBucket"
Prevention
- Always include s3:ListBucket alongside s3:GetObject in artifact IAM policies
- Use workflow-level service accounts with a shared, tested S3 policy
- Smoke-test artifact loading in CI against the real bucket
- Prefer explicit file keys over directory prefixes to skip IsDirectory probes
When it happens
Trigger: loadS3Artifact got NoSuchKey from GetFile, then s3cli.IsDirectory(bucket, key) failed — typically an S3 API error (HeadObject/ListObjects failure), auth failure on list/head permissions, throttling, or network error during the directory probe.
Common situations: IAM policy grants GetObject but denies ListBucket (IsDirectory needs list); S3-compatible endpoints (MinIO, GCS-interop) that fail ListObjectsV2 oddly; expired/stale credentials; rate limiting during heavy parallel artifact downloads.
Related errors
- failed to get file: %w
- failed to get directory: %w
- unable to list files in %s: %w
- failed to create bucket %s: %w
- failed to list directory: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/eb1e5f55712be8aa.
Report an issue: GitHub.