argoproj/argo-workflows · error

plugin %s load failed: %w

Error message

plugin %s load failed: %w

What it means

Driver.Load calls the plugin's LoadArtifact RPC. This error wraps a transport/RPC-level failure (gRPC status error, connection dropped, context deadline) — the call itself failed rather than the plugin reporting a business-logic failure.

Source

Thrown at workflow/artifacts/plugin/plugin.go:154

}

// Close closes the gRPC connection
func (d *Driver) Close() error {
	if d.conn != nil {
		return d.conn.Close()
	}
	return nil
}

// Load implements ArtifactDriver.Load by calling the plugin service
func (d *Driver) Load(ctx context.Context, inputArtifact *wfv1.Artifact, path string) error {
	grpcArtifact := convertToGRPC(inputArtifact)
	resp, err := d.client.Load(ctx, &artifact.LoadArtifactRequest{
		InputArtifact: grpcArtifact,
		Path:          path,
	})
	if err != nil {
		return fmt.Errorf("plugin %s load failed: %w", d.pluginName, err)
	}
	if !resp.Success {
		return fmt.Errorf("plugin %s load failed: %s", d.pluginName, resp.Error)
	}
	return nil
}

// OpenStream implements ArtifactDriver.OpenStream by calling the plugin service
func (d *Driver) OpenStream(ctx context.Context, a *wfv1.Artifact) (io.ReadCloser, error) {
	grpcArtifact := convertToGRPC(a)
	stream, err := d.client.OpenStream(ctx, &artifact.OpenStreamRequest{
		Artifact: grpcArtifact,
	})
	if err != nil {
		return nil, fmt.Errorf("plugin %s open stream failed: %w", d.pluginName, err)
	}

	reader, writer := io.Pipe()

View on GitHub (pinned to 35bff19146)

Solutions

  1. Check plugin pod stability (restarts, OOMKills) with kubectl get pod / describe
  2. Use errors.Is / status.Code(err) on the wrapped error to branch: retry Unavailable/DeadlineExceeded with backoff, fail fast on Unimplemented
  3. Increase the context/step timeout for large artifact loads
  4. Upgrade the plugin to match the controller's artifact gRPC API version

Example fix

// before: treat any failure as fatal
return d.Load(ctx, art, path)
// after: retry transient gRPC failures
err := d.Load(ctx, art, path)
if status.Code(err) == codes.Unavailable {
    return retryWithBackoff(func() error { return d.Load(ctx, art, path) })
}
return err
Defensive patterns

Strategy: retry

Validate before calling

// preflight the plugin before the artifact step
resp, err := drv.ListObjects(ctx, artifactRef)
if err != nil { return fmt.Errorf("plugin unreachable for artifact load: %w", err) }

Try / catch

err := drv.Load(ctx, art, path)
if err != nil {
    switch status.Code(err) {
    case codes.Unavailable, codes.DeadlineExceeded, codes.Canceled:
        return retryWithBackoff(3, func() error { return drv.Load(ctx, art, path) })
    case codes.Unimplemented:
        return fmt.Errorf("plugin too old for Load RPC: %w", err)
    default:
        return err
    }
}

Prevention

When it happens

Trigger: The Load RPC returns a gRPC error: Unavailable (plugin restarted mid-workflow), DeadlineExceeded (ctx timeout during a large copy), Canceled (workflow/node cancelled), Unimplemented (plugin predates the Load RPC), or the connection broke mid-call.

Common situations: Plugin pod OOM-killed or restarted while an artifact was being loaded, network/context timeouts on large artifacts, plugin version older than the controller expecting a newer RPC surface.

Related errors


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