argoproj/argo-workflows · error

Failed to save artifact: %v

Error message

Failed to save artifact: %v

What it means

After the driver is created, the file stream is written to storage with driver.SaveStream(ctx, file, outputArtifact). Any storage-side failure — network errors, authentication rejection, bucket missing, quota exceeded, context cancellation — is surfaced as HTTP 500 "Failed to save artifact: ..." with the underlying driver error appended.

Source

Thrown at server/artifacts/artifact_server.go:267

		return
	}

	a.logger.WithFields(logging.Fields{
		"originalKey": originalKey,
		"newKey":      newKey,
	}).Info(ctx, "Uploading artifact with new key")

	// Get the driver for the artifact
	kubeClient := auth.GetKubeClient(ctx)
	driver, err := a.artDriverFactory(ctx, outputArtifact, resources{kubeClient, namespace})
	if err != nil {
		http.Error(w, fmt.Sprintf("Failed to create artifact driver: %v", err), http.StatusInternalServerError)
		return
	}

	// Upload using SaveStream
	if err := driver.SaveStream(ctx, file, outputArtifact); err != nil {
		http.Error(w, fmt.Sprintf("Failed to save artifact: %v", err), http.StatusInternalServerError)
		return
	}

	a.logger.WithFields(logging.Fields{
		"artifactName": artifactName,
		"key":          newKey,
	}).Info(ctx, "Successfully uploaded artifact")

	// Return only name/key. The resolved ArtifactLocation contains bucket
	// endpoints and Secret selector names that the client does not need.
	response := map[string]any{
		"name": artifactName,
		"key":  newKey,
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(response); err != nil {

View on GitHub (pinned to 35bff19146)

Solutions

  1. Read the detailed driver error appended to the response; fix the indicated storage issue (bucket, permissions, endpoint).
  2. Verify the bucket exists and credentials have write access (e.g. s3:PutObject).
  3. Test connectivity from the argo-server pod to the storage endpoint (DNS, TLS, firewall).
  4. For large files, check proxy/body-size/timeout settings including ARGO_SERVER_MAX_ARTIFACT_UPLOAD_BYTES.
  5. Retry the upload once transient network issues are resolved.

Example fix

// before (endpoint misconfigured)
s3:
  endpoint: my-minio:900
// after
s3:
  endpoint: my-minio:9000
  insecure: true
Defensive patterns

Strategy: retry

Validate before calling

# Pre-flight: bucket reachable and writable from your network
kubectl -n argo run --rm -i test-s3 --image=minio/mc -- \
  sh -c 'mc alias set t $ENDPOINT $KEY $SECRET && mc ls t/$BUCKET'

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  try { return await uploadArtifact(file); }
  catch (e) {
    if (e.status === 500 && e.body.includes('Failed to save artifact') && isTransient(e)) {
      await sleep(backoff(attempt)); continue;
    }
    throw e;
  }
}

Prevention

When it happens

Trigger: Storage endpoint unreachable (wrong endpoint/region, DNS failure, firewall); bucket does not exist or the credentials lack write permission; object size exceeds limits or upload times out; the request context is canceled mid-upload (client disconnect); S3 signature/credential errors at write time.

Common situations: MinIO/S3 endpoint misconfigured (http vs https, wrong port); IAM/service account without putObject permission; bucket name typo; large uploads cut off by proxies with short idle timeouts; expired cloud credentials.

Related errors


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