{"record":{"id":"9308a9bfb9a6aa76","repo":"argoproj/argo-workflows","slug":"plugin-s-list-objects-failed-s","errorCode":null,"errorMessage":"plugin %s list objects failed: %s","messagePattern":"plugin (.+?) list objects failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/plugin/plugin.go","lineNumber":351,"sourceCode":"\t\treturn fmt.Errorf(\"plugin %s delete failed: %w\", d.pluginName, err)\n\t}\n\tif !resp.Success {\n\t\treturn fmt.Errorf(\"plugin %s delete failed: %s\", d.pluginName, resp.Error)\n\t}\n\treturn nil\n}\n\n// ListObjects implements ArtifactDriver.ListObjects by calling the plugin service\nfunc (d *Driver) ListObjects(ctx context.Context, artifactRef *wfv1.Artifact) ([]string, error) {\n\tgrpcArtifact := convertToGRPC(artifactRef)\n\tresp, err := d.client.ListObjects(ctx, &artifact.ListObjectsRequest{\n\t\tArtifact: grpcArtifact,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"plugin %s list objects failed: %w\", d.pluginName, err)\n\t}\n\tif resp.Error != \"\" {\n\t\treturn nil, fmt.Errorf(\"plugin %s list objects failed: %s\", d.pluginName, resp.Error)\n\t}\n\treturn resp.Objects, nil\n}\n\n// IsDirectory implements ArtifactDriver.IsDirectory by calling the plugin service\nfunc (d *Driver) IsDirectory(ctx context.Context, artifactRef *wfv1.Artifact) (bool, error) {\n\tgrpcArtifact := convertToGRPC(artifactRef)\n\tresp, err := d.client.IsDirectory(ctx, &artifact.IsDirectoryRequest{\n\t\tArtifact: grpcArtifact,\n\t})\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"plugin %s is directory check failed: %w\", d.pluginName, err)\n\t}\n\tif resp.Error != \"\" {\n\t\treturn false, fmt.Errorf(\"plugin %s is directory check failed: %s\", d.pluginName, resp.Error)\n\t}\n\treturn resp.IsDirectory, nil\n}","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/plugin/plugin.go#L333-L369","documentation":"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).","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// narrowing by prefix and handling backend 'not found'\n// before:\nobjs, err := driver.ListObjects(ctx, art)\nif err != nil { return err }\n// after:\nobjs, err := driver.ListObjects(ctx, art)\nif err != nil {\n\tif strings.Contains(err.Error(), \"NoSuchBucket\") {\n\t\treturn fmt.Errorf(\"plugin bucket %q missing; check artifact plugin config\", art.Bucket)\n\t}\n\treturn err\n}","handlingStrategy":"try-catch","validationCode":"// check plugin storage config health before listing\nresp, err := pluginClient.GetCapabilities(ctx, &artifact.GetCapabilitiesRequest{})\nif err != nil {\n\treturn fmt.Errorf(\"plugin misconfigured or unreachable: %w\", err)\n}\n_ = resp // plugin reachable; storage creds still validated server-side at list time","typeGuard":"func isBackendListFailure(err error) bool {\n\t// error 514: RPC succeeded, plugin returned Error string\n\treturn err != nil && status.Code(err) == codes.Unknown && strings.Contains(err.Error(), \"list objects failed\")\n}","tryCatchPattern":"objs, err := driver.ListObjects(ctx, art)\nif err != nil {\n\tif isBackendListFailure(err) {\n\t\tswitch {\n\t\tcase strings.Contains(err.Error(), \"AccessDenied\"), strings.Contains(err.Error(), \"Forbidden\"):\n\t\t\treturn nil, fmt.Errorf(\"check plugin storage credentials/permissions: %w\", err)\n\t\tcase strings.Contains(err.Error(), \"Throttl\"), strings.Contains(err.Error(), \"rate\"):\n\t\t\treturn nil, retryableErr // back off and retry\n\t\t}\n\t}\n\treturn nil, err\n}","preventionTips":["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."],"tags":["plugin","artifacts","list","storage-backend"],"backgroundTag":"plugin-reported-failure","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}