argoproj/argo-workflows · error
failed to stream artifact: %v
Error message
failed to stream artifact: %v
What it means
returnArtifact streams an artifact to the HTTP response; if io.Copy fails while writing the artifact bytes to the client, it writes a 500 and returns this error. Causes are typically client disconnects or I/O problems writing the response body.
Source
Thrown at server/artifacts/artifact_server.go:780
return err
}
defer func() {
if closeErr := stream.Close(); closeErr != nil {
logger.WithError(closeErr).WithField("stream", stream).Warn(ctx, "Error closing stream")
}
}()
key, _ := art.GetKey()
w.Header().Add("Content-Disposition", fmt.Sprintf(`filename="%s"`, path.Base(key)))
w.Header().Add("Content-Type", mime.TypeByExtension(path.Ext(key)))
a.setSecurityHeaders(w)
_, err = io.Copy(w, stream)
if err != nil {
errStr := fmt.Sprintf("failed to stream artifact: %v", err)
http.Error(w, errStr, http.StatusInternalServerError)
return errors.New(errStr)
}
w.WriteHeader(http.StatusOK)
return nil
}
func (a *ArtifactServer) getWorkflowAndValidate(ctx context.Context, namespace string, workflowName string) (*wfv1.Workflow, error) {
wfClient := auth.GetWfClient(ctx)
wf, err := wfClient.ArgoprojV1alpha1().Workflows(namespace).Get(ctx, workflowName, metav1.GetOptions{})
if err != nil {
return nil, err
}
err = a.instanceIDService.Validate(wf)
if err != nil {
return nil, err
}
err = a.hydrator.Hydrate(ctx, wf)
if err != nil {
return nil, errView on GitHub (pinned to 35bff19146)
Solutions
- Retry the download from the UI/CLI — transient disconnects are the most common cause.
- Check ingress/proxy timeout settings (e.g. nginx proxy-read-timeout) for large artifacts and raise them.
- Inspect argo-server logs for the wrapped %v cause to distinguish client-cancel vs server I/O errors.
- Verify network stability / reduce artifact size if transfers keep failing mid-stream.
Example fix
// client-side retry pattern (Go)
// before
resp, err := http.Get(url)
// after
var resp *http.Response
for i := 0; i < 3 && err != nil; i++ {
resp, err = http.Get(url)
}
if err != nil { return fmt.Errorf("download failed after retries: %w", err) } Defensive patterns
Strategy: retry
Validate before calling
// preflight: ensure artifact exists and is fetchable
resp, err := http.Head(artifactURL)
if err != nil || resp.StatusCode != http.StatusOK {
return fmt.Errorf("artifact not ready: status %v", resp.StatusCode)
} Try / catch
resp, err := http.Get(artifactURL)
if err != nil || strings.Contains(errBody, "failed to stream artifact") {
// backoff and retry the download
time.Sleep(2*time.Second)
resp, err = http.Get(artifactURL)
} Prevention
- Retry transient download failures with backoff
- Raise ingress/proxy timeouts for large artifacts
- Avoid cancelling UI requests that stream artifacts
- Check argo-server logs for the underlying io.Copy cause
When it happens
Trigger: GET artifact endpoints (getArtifact, GetArtifactFile, getArtifactByUID via the artifact server) where the copy from the opened stream to the http.ResponseWriter fails — client closed the connection mid-download, network interruption, or the underlying stream reader errored after headers were being written.
Common situations: Browsers/users cancelling large artifact downloads; proxy or ingress timeouts killing long transfers; flaky network between client and argo-server; UI fetching artifact logs while navigating away.
Related errors
- failed to get and store artifact data: %w
- CodeNotFound
- request failed with: %w
- unable to upload stream to Azure blob %s: %w
- new bucket reader: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/382eb43e24cbdb51.
Report an issue: GitHub.