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, err

View on GitHub (pinned to 35bff19146)

Solutions

  1. Retry the download from the UI/CLI — transient disconnects are the most common cause.
  2. Check ingress/proxy timeout settings (e.g. nginx proxy-read-timeout) for large artifacts and raise them.
  3. Inspect argo-server logs for the wrapped %v cause to distinguish client-cancel vs server I/O errors.
  4. 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

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


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