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
- Read the detailed driver error appended to the response; fix the indicated storage issue (bucket, permissions, endpoint).
- Verify the bucket exists and credentials have write access (e.g. s3:PutObject).
- Test connectivity from the argo-server pod to the storage endpoint (DNS, TLS, firewall).
- For large files, check proxy/body-size/timeout settings including ARGO_SERVER_MAX_ARTIFACT_UPLOAD_BYTES.
- 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
- Verify endpoint scheme/port (http vs https, correct MinIO port) before first upload.
- Grant storage write permissions (e.g. s3:PutObject) to the credentials in use.
- Keep uploads under ARGO_SERVER_MAX_ARTIFACT_UPLOAD_BYTES and proxy body limits.
- Increase proxy idle timeouts for large uploads; monitor storage quota.
- Rotate cloud credentials before expiry in long-lived installs.
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
- failed to put file: %w
- error appending filename %s to key of artifact %+v: err: %w
- failed to get directory: %w
- failed to put directory: %w
- failed to check if key %s exists from bucket %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/aed191a1f18a6b6d.
Report an issue: GitHub.