{"record":{"id":"a12ae880e585d88d","repo":"argoproj/argo-workflows","slug":"plugin-s-connection-shutdown-socket-q","errorCode":null,"errorMessage":"plugin %s connection shutdown (socket=%q)","messagePattern":"plugin (.+?) connection shutdown \\(socket=%q\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/plugin/plugin.go","lineNumber":124,"sourceCode":"\t}\n\n\tdriver := &Driver{\n\t\tpluginName: pluginName,\n\t\tconn:       conn,\n\t\tclient:     artifact.NewArtifactServiceClient(conn),\n\t}\n\n\t// Verify the connection by checking the connection state\n\tctx, cancel := context.WithTimeout(ctx, connectionTimeout)\n\tdefer cancel()\n\n\tconn.Connect()\n\n\t// Wait for the connection to reach Ready state within the timeout\n\tfor state := conn.GetState(); state != connectivity.Ready; state = conn.GetState() {\n\t\tif state == connectivity.Shutdown {\n\t\t\t_ = conn.Close()\n\t\t\treturn nil, fmt.Errorf(\"plugin %s connection shutdown (socket=%q)\", pluginName, socketPath)\n\t\t}\n\t\tif !conn.WaitForStateChange(ctx, state) {\n\t\t\t// Timeout or context cancelled\n\t\t\tcurrentState := conn.GetState()\n\t\t\t_ = conn.Close()\n\t\t\treturn nil, fmt.Errorf(\"timeout waiting for plugin %s connection to become ready, last state: %s (socket=%q)\", pluginName, currentState, socketPath)\n\t\t}\n\t}\n\n\tlogger.Info(ctx, fmt.Sprintf(\"plugin %s: connected successfully to %q\", pluginName, socketPath))\n\treturn driver, nil\n}\n\n// Close closes the gRPC connection\nfunc (d *Driver) Close() error {\n\tif d.conn != nil {\n\t\treturn d.conn.Close()\n\t}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/plugin/plugin.go#L106-L142","documentation":"After dialing, NewDriver waits for the gRPC channel to reach connectivity.Ready. If the channel enters connectivity.Shutdown — meaning the connection was closed (including the driver's own conn.Close() on a prior failure path) — construction aborts with this error. It signals the gRPC channel is dead and cannot become ready.","triggerScenarios":"The channel transitions to Shutdown while waiting for Ready: the ClientConn was closed by another goroutine, grpc-go gave up reconnecting, or the transport was shut down due to repeated failures against the unix socket.","commonSituations":"Plugin process exits immediately after creating its socket (crash after bind), socket file exists but nothing is listening (stale socket left over from a previous run), concurrent Close() of the same Driver in tests.","solutions":["Verify the plugin process is actually running and serving on the socket (ss -x | grep <socket> or attempt a grpc probe)","Remove stale socket files left by crashed plugin instances and restart the plugin","Check plugin logs for a panic/exit right after binding the socket","Ensure no code path calls Driver.Close() concurrently with NewDriver (common in tests with shared drivers)"],"exampleFix":"// before: stale socket from previous run, no listener\n// after: clean up before plugin start\n// rm -f /var/run/argo/plugins/myplug.sock && ./my-plugin --socket /var/run/argo/plugins/myplug.sock","handlingStrategy":"fallback","validationCode":"// confirm something is listening before dialing\nif conn, err := net.Dial(\"unix\", socketPath); err != nil {\n    return fmt.Errorf(\"nothing listening on %s: %w\", socketPath, err)\n} else { conn.Close() }","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"connection shutdown\") {\n    // channel is closed: never reuse this Driver; rebuild it\n    drv.Close()\n    drv, err = plugin.NewDriver(ctx, name, path, timeout)\n}","preventionTips":["Delete stale socket files before starting the plugin","Never call Driver.Close() concurrently with other users of the connection","Add a plugin liveness/readiness probe so crash-after-bind is caught early"],"tags":["grpc","connectivity","unix-socket","plugin-driver"],"backgroundTag":"grpc-connection-shutdown","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}