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
- Read the plugin's message (%s) — it typically names the backend error (NoSuchBucket, AccessDenied, throttling) and fix the corresponding configuration.
- Verify the plugin's storage credentials/secret are current and include list permissions.
- Confirm the bucket/container and prefix exist and match the plugin's configured backend.
- 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
- Rotate storage credentials in the plugin's secret promptly; expired creds surface as plugin-reported list failures.
- Grant the plugin's service account list permissions on the bucket/container/prefix.
- Create buckets/containers up front and validate plugin config with a smoke-test list on deploy.
- Add client-side rate limiting for large listings to avoid backend throttling.
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
- plugin %s delete failed: %s
- plugin %s list objects failed: %w
- failed to create plugin driver for %s: %w
- plugin %s stream error: %s
- plugin %s save failed: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/9308a9bfb9a6aa76.
Report an issue: GitHub.