{"record":{"id":"82addf8083f994d2","repo":"argoproj/argo-workflows","slug":"plugin-s-stream-error-s","errorCode":null,"errorMessage":"plugin %s stream error: %s","messagePattern":"plugin (.+?) stream error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/plugin/plugin.go","lineNumber":186,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"plugin %s open stream failed: %w\", d.pluginName, err)\n\t}\n\n\treader, writer := io.Pipe()\n\n\tgo func() {\n\t\tdefer writer.Close()\n\t\tfor {\n\t\t\tresp, err := stream.Recv()\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\twriter.CloseWithError(fmt.Errorf(\"plugin %s stream receive failed: %w\", d.pluginName, err))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif resp.Error != \"\" {\n\t\t\t\twriter.CloseWithError(fmt.Errorf(\"plugin %s stream error: %s\", d.pluginName, resp.Error))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif resp.IsEnd {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif len(resp.Data) > 0 {\n\t\t\t\tif _, writeErr := writer.Write(resp.Data); writeErr != nil {\n\t\t\t\t\twriter.CloseWithError(fmt.Errorf(\"plugin %s stream write failed: %w\", d.pluginName, writeErr))\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn reader, nil\n}\n\n// Save implements ArtifactDriver.Save by calling the plugin service","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/plugin/plugin.go#L168-L204","documentation":"This error surfaces when the artifact plugin itself reports an error message inside an otherwise-healthy OpenStream gRPC response: the driver is receiving chunks from the plugin's stream and a response carries a non-empty resp.Error field. The driver wraps the plugin's own error string and injects it into the io.Pipe via CloseWithError, so the caller of Load/any reader of the returned ReadCloser sees it as a read error. It means the plugin started streaming but failed on its side (e.g. could not read the source storage).","triggerScenarios":"Calling Driver.OpenStream (artifact plugin driver, workflow/artifacts/plugin/plugin.go:163) where the plugin's stream.Recv returns a response with resp.Error set — i.e. the plugin's gRPC server hit an error mid-stream and reported it in-band rather than as a gRPC status.","commonSituations":"Plugin cannot access the backing storage (bad S3/GCS credentials configured on the plugin), artifact key does not exist, plugin-side timeout while reading a large artifact, or plugin misconfigured storage backend.","solutions":["Read the embedded plugin error message after 'stream error: ' — it is the plugin's own diagnosis and names the real cause","Check the plugin's logs (kubectl logs on the plugin container) for the corresponding failure","Verify the artifact's source location/credentials are valid and accessible from the plugin pod","Retry the artifact load once storage issues are fixed"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// No pre-call validation can predict plugin-internal failures; ensure the plugin is reachable first:\nif _, err := os.Stat(socketPath); err != nil {\n    return fmt.Errorf(\"plugin socket %s missing before OpenStream: %w\", socketPath, err)\n}","typeGuard":"func pluginStreamError(err error) (string, bool) {\n    var pe *io.PipeError // or match on message prefix\n    if errors.As(err, &pe) && strings.Contains(err.Error(), \"stream error: \") {\n        return err.Error(), true\n    }\n    return \"\", false\n}","tryCatchPattern":"reader, err := driver.OpenStream(ctx, artifact)\nif err != nil { return err }\nif _, copyErr := io.Copy(dst, reader); copyErr != nil {\n    if strings.Contains(copyErr.Error(), \"stream error: \") {\n        // plugin-reported failure: inspect plugin logs, fix storage creds/config, retry\n    }\n    reader.Close()\n    return copyErr\n}\nreader.Close()","preventionTips":["Verify plugin storage credentials and destination config before submitting workflows","Keep plugin pods resourced for the artifact sizes you stream","Read the text after 'stream error: ' — it is the plugin's own diagnosis","Test plugin Load paths with a small artifact before large production runs"],"tags":["grpc","plugin","streaming","artifacts"],"backgroundTag":"plugin-stream-error","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"}