argoproj/argo-workflows · error

unable to list files in %s: %w

Error message

unable to list files in %s: %w

What it means

Delete of an artifact whose key ends with '/' is treated as a directory: the driver lists all objects under the prefix before deleting them. This error wraps a ListDirectory failure, so nothing was deleted.

Source

Thrown at workflow/artifacts/s3/s3.go:312

	defer cancel()
	log := logging.RequireLoggerFromContext(ctx)
	err := retry.OnError(retry.DefaultBackoff, func(err error) bool {
		return isTransientS3Err(ctx, err)
	}, func() error {
		log.WithField("key", artifact.S3.Key).Info(ctx, "S3 Delete")
		s3cli, err := s3Driver.newClient(ctx)
		if err != nil {
			return err
		}

		// check suffix instead of s3cli.IsDirectory as it requires another request for file delete (most scenarios)
		if !strings.HasSuffix(artifact.S3.Key, "/") {
			return s3cli.Delete(artifact.S3.Bucket, artifact.S3.Key)
		}

		keys, err := s3cli.ListDirectory(artifact.S3.Bucket, artifact.S3.Key)
		if err != nil {
			return fmt.Errorf("unable to list files in %s: %w", artifact.S3.Key, err)
		}
		for _, objKey := range keys {
			err = s3cli.Delete(artifact.S3.Bucket, objKey)
			if err != nil {
				return err
			}
		}
		return nil
	})

	return err
}

// saveS3Artifact uploads artifacts to an S3 compliant storage
// returns true if the upload is completed or can't be retried (non-transient error)
// returns false if it can be retried (transient error)
func saveS3Artifact(ctx context.Context, s3cli Client, path string, outputArtifact *wfv1.Artifact) (bool, error) {
	isDir, err := file.IsDirectory(path)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Grant s3:ListBucket to the deleting principal's credentials
  2. Retry — Delete already retries on transient errors with DefaultBackoff
  3. If the key is actually a single object, remove the trailing '/' from the artifact key so the simple Delete path is used
  4. Check endpoint compatibility (ListObjectsV2) for MinIO/GCS-interop

Example fix

// before: key treated as directory
key: "my/artifacts/"
// after (single object)
key: "my/artifacts"
Defensive patterns

Strategy: validation

Validate before calling

// before deleting a directory artifact, confirm list access
keys, err := s3cli.ListDirectory(bucket, key)
if err != nil { return fmt.Errorf("cannot list prefix %s: %w", key, err) }

Prevention

When it happens

Trigger: ArtifactDriver.Delete called with artifact.S3.Key ending in '/': s3cli.ListDirectory(bucket, key) failed — ListBucket permission denied, throttling, network error, or endpoint incompatibility.

Common situations: Deleting archived directory artifacts with credentials lacking s3:ListBucket; garbage-collection of large prefixes hitting list pagination limits or rate limits; S3-compatible providers with listing quirks.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/fcbde5a727d64fdb. Report an issue: GitHub.