argoproj/argo-workflows · error
failed to list directory: %w
Error message
failed to list directory: %w
What it means
Wraps a failure from s3cli.ListDirectory when loading an S3 artifact directory. Called inside the retry backoff of listS3Artifact; transient errors are retried, non-transient ones fail the load. Means the S3 API call enumerating objects under the artifact key prefix failed.
Source
Thrown at workflow/artifacts/s3/s3.go:398
s3cli, err := s3Driver.newClient(ctx)
if err != nil {
return !isTransientS3Err(ctx, err), fmt.Errorf("failed to create new S3 client: %w", err)
}
done, files, err = listObjects(ctx, s3cli, artifact)
return done, err
})
return files, err
}
// listObjects returns the files inside the directory represented by the Artifact
// returns true if success or can't be retried (non-transient error)
// returns false if it can be retried (transient error)
func listObjects(ctx context.Context, s3cli Client, artifact *wfv1.Artifact) (bool, []string, error) {
var files []string
files, err := s3cli.ListDirectory(artifact.S3.Bucket, artifact.S3.Key)
if err != nil {
return !isTransientS3Err(ctx, err), files, fmt.Errorf("failed to list directory: %w", err)
}
log := logging.RequireLoggerFromContext(ctx)
log.WithFields(logging.Fields{"bucket": artifact.S3.Bucket, "key": artifact.S3.Key, "files": files}).Debug(ctx, "successfully listing S3 directory")
if len(files) == 0 {
directoryExists, err := s3cli.KeyExists(artifact.S3.Bucket, artifact.S3.Key)
if err != nil {
return !isTransientS3Err(ctx, err), files, fmt.Errorf("failed to check if key %s exists from bucket %s: %w", artifact.S3.Key, artifact.S3.Bucket, err)
}
if !directoryExists {
return true, files, argoerrs.New(argoerrs.CodeNotFound, fmt.Sprintf("no key found of name %s", artifact.S3.Key))
}
}
return true, files, nil
}
func (s3Driver *ArtifactDriver) IsDirectory(ctx context.Context, artifact *wfv1.Artifact) (bool, error) {
s3cli, err := s3Driver.newClient(ctx)View on GitHub (pinned to 35bff19146)
Solutions
- Check the wrapped cause for the concrete S3 error (NoSuchBucket, AccessDenied, timeout)
- Verify the artifact's s3.bucket and key are correct and the bucket exists
- Grant the artifact credentials s3:ListBucket (and GetObject) on the bucket
- Confirm endpoint connectivity from the cluster/pod
Example fix
// before (IAM)
// no ListBucket permission
// after
{"Effect":"Allow","Action":["s3:ListBucket","s3:GetObject"],"Resource":["arn:aws:s3:::my-bucket","arn:aws:s3:::my-bucket/*"]} Defensive patterns
Strategy: retry
Validate before calling
aws --endpoint-url $ENDPOINT s3api head-bucket --bucket $BUCKET aws --endpoint-url $ENDPOINT s3api list-objects-v2 --bucket $BUCKET --prefix $KEY --max-items 1
Try / catch
// wrap load and inspect cause
files, err := ctx.LoadArtifact(artifact)
if err != nil {
var ae smithy.APIError
if errors.As(errors.Unwrap(err), &ae) && ae.ErrorCode() == "AccessDenied" { fixIAM() }
} Prevention
- Grant s3:ListBucket + s3:GetObject to artifact credentials
- Validate bucket name and key prefix in the artifact spec
- Prefer referencing artifacts by name from prior steps rather than hand-typed buckets/keys
When it happens
Trigger: listObjects calls s3cli.ListDirectory(bucket, key) and Minio returns an error: bucket does not exist, access denied to list, network error, or invalid key prefix.
Common situations: Bucket typo in artifact spec; IAM policy lacks s3:ListBucket; S3 endpoint unreachable from pod; loading an artifact whose bucket was deleted.
Related errors
- failed to test if %s is a directory: %w
- failed to check if key %s exists from bucket %s: %w
- failed to create parent directory for artifact %q at %s: %w
- failed to clear existing path for artifact %q at %s: %w
- failed to symlink input artifact %q (%s -> %s): %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/4548a19c31f145dd.
Report an issue: GitHub.