argoproj/argo-workflows · error

plugin %s list objects failed: %s

Error message

plugin %s list objects failed: %s

What it means

When the ListObjects RPC succeeds but the plugin sets a non-empty Error string in the response, the driver raises "plugin %s list objects failed: %s" with that message and returns no objects. The gRPC transport is fine; the plugin's storage backend failed the listing (e.g. missing bucket, bad credentials, throttling).

Source

Thrown at workflow/artifacts/plugin/plugin.go:351

		return fmt.Errorf("plugin %s delete failed: %w", d.pluginName, err)
	}
	if !resp.Success {
		return fmt.Errorf("plugin %s delete failed: %s", d.pluginName, resp.Error)
	}
	return nil
}

// ListObjects implements ArtifactDriver.ListObjects by calling the plugin service
func (d *Driver) ListObjects(ctx context.Context, artifactRef *wfv1.Artifact) ([]string, error) {
	grpcArtifact := convertToGRPC(artifactRef)
	resp, err := d.client.ListObjects(ctx, &artifact.ListObjectsRequest{
		Artifact: grpcArtifact,
	})
	if err != nil {
		return nil, fmt.Errorf("plugin %s list objects failed: %w", d.pluginName, err)
	}
	if resp.Error != "" {
		return nil, fmt.Errorf("plugin %s list objects failed: %s", d.pluginName, resp.Error)
	}
	return resp.Objects, nil
}

// IsDirectory implements ArtifactDriver.IsDirectory by calling the plugin service
func (d *Driver) IsDirectory(ctx context.Context, artifactRef *wfv1.Artifact) (bool, error) {
	grpcArtifact := convertToGRPC(artifactRef)
	resp, err := d.client.IsDirectory(ctx, &artifact.IsDirectoryRequest{
		Artifact: grpcArtifact,
	})
	if err != nil {
		return false, fmt.Errorf("plugin %s is directory check failed: %w", d.pluginName, err)
	}
	if resp.Error != "" {
		return false, fmt.Errorf("plugin %s is directory check failed: %s", d.pluginName, resp.Error)
	}
	return resp.IsDirectory, nil
}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Read the plugin's message (%s) — it typically names the backend error (NoSuchBucket, AccessDenied, throttling) and fix the corresponding configuration.
  2. Verify the plugin's storage credentials/secret are current and include list permissions.
  3. Confirm the bucket/container and prefix exist and match the plugin's configured backend.
  4. If the backend throttles, retry with backoff or reduce listing scope.

Example fix

// narrowing by prefix and handling backend 'not found'
// before:
objs, err := driver.ListObjects(ctx, art)
if err != nil { return err }
// after:
objs, err := driver.ListObjects(ctx, art)
if err != nil {
	if strings.Contains(err.Error(), "NoSuchBucket") {
		return fmt.Errorf("plugin bucket %q missing; check artifact plugin config", art.Bucket)
	}
	return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// check plugin storage config health before listing
resp, err := pluginClient.GetCapabilities(ctx, &artifact.GetCapabilitiesRequest{})
if err != nil {
	return fmt.Errorf("plugin misconfigured or unreachable: %w", err)
}
_ = resp // plugin reachable; storage creds still validated server-side at list time

Type guard

func isBackendListFailure(err error) bool {
	// error 514: RPC succeeded, plugin returned Error string
	return err != nil && status.Code(err) == codes.Unknown && strings.Contains(err.Error(), "list objects failed")
}

Try / catch

objs, err := driver.ListObjects(ctx, art)
if err != nil {
	if isBackendListFailure(err) {
		switch {
		case strings.Contains(err.Error(), "AccessDenied"), strings.Contains(err.Error(), "Forbidden"):
			return nil, fmt.Errorf("check plugin storage credentials/permissions: %w", err)
		case strings.Contains(err.Error(), "Throttl"), strings.Contains(err.Error(), "rate"):
			return nil, retryableErr // back off and retry
		}
	}
	return nil, err
}

Prevention

When it happens

Trigger: Calling Driver.ListObjects where the plugin's backend listing fails: bucket/container doesn't exist, storage credentials invalid or expired, permission denied on the prefix, or backend rate-limit/throttle error mapped by the plugin into resp.Error.

Common situations: Plugin configured with wrong bucket name or region; rotated cloud credentials not updated in the plugin's secret; IAM policy change removing ListBucket permission; listing a prefix that was never written to (backend returns prefix-not-found style errors).

Related errors


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