{"record":{"id":"d145ec40eed0efe2","repo":"argoproj/argo-workflows","slug":"plugin-s-cannot-stat-unix-socket-at-q-w","errorCode":null,"errorMessage":"plugin %s cannot stat unix socket at %q: %w","messagePattern":"plugin (.+?) cannot stat unix socket at %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/plugin/plugin.go","lineNumber":52,"sourceCode":"\t// Check for the unix socket, retrying for up to two minutes if it doesn't exist immediately\n\tlogger := logging.RequireLoggerFromContext(ctx)\n\n\t// Try for up to 120 seconds, checking once per second\n\tconst maxRetries = 120\n\tvar info os.FileInfo\n\tvar statErr error\n\tvar socketExists bool\n\n\tfor retry := range maxRetries {\n\t\tinfo, statErr = os.Stat(socketPath)\n\t\tif statErr == nil {\n\t\t\tsocketExists = true\n\t\t\tbreak\n\t\t}\n\n\t\tif !os.IsNotExist(statErr) {\n\t\t\t// If error is not due to missing file, fail immediately\n\t\t\treturn nil, fmt.Errorf(\"plugin %s cannot stat unix socket at %q: %w\", pluginName, socketPath, statErr)\n\t\t}\n\n\t\t// Socket doesn't exist yet, log at debug level and retry\n\t\tlogger.WithFields(logging.Fields{\n\t\t\t\"pluginName\": pluginName,\n\t\t\t\"socketPath\": socketPath,\n\t\t\t\"retry\":      retry,\n\t\t\t\"maxRetries\": maxRetries,\n\t\t}).Debug(ctx, \"plugin socket not found, retrying in 1s\")\n\n\t\t// Use context-aware sleep\n\t\tselect {\n\t\tcase <-time.After(time.Second):\n\t\t\t// Continue to next iteration\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, fmt.Errorf(\"plugin %s context cancelled while waiting for socket at %q: %w\", pluginName, socketPath, ctx.Err())\n\t\t}\n\t}","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/plugin/plugin.go#L34-L70","documentation":"NewDriver verifies the plugin's unix socket file exists before dialing. If os.Stat fails with an error that is NOT 'file not found' (e.g. permission denied on a parent directory, or a path component is not a directory), the driver fails immediately instead of retrying, wrapping the underlying stat error.","triggerScenarios":"Calling NewDriver with a socketPath whose parent directory is unreadable/executable-by-permission, the path traverses a nonexistent directory component (ENOTDIR), the path is too long (ENAMETOOLONG), or filesystem/I/O errors while statting — anything other than ENOENT.","commonSituations":"Wrong socketPath typo pointing at a regular file inside an inaccessible directory, container volume mounts where the plugin's socket directory has wrong ownership/permissions, or the path contains a file where a directory is expected after a config change.","solutions":["Check permissions on every directory component of socketPath; make them readable/searchable by the workflow executor user","Verify the socketPath is a directory path plus socket filename, not a path that runs through a regular file","Confirm the plugin pod's emptyDir/hostPath volume is mounted at the expected location (kubectl exec and ls -la the directory)","If the filesystem is flaky, increase logging and inspect the wrapped statErr (e.g. 'permission denied' vs 'not a directory') to target the fix"],"exampleFix":"// before: socketPath = \"/var/run/argo/plugins/myplug.sock\" but /var/run/argo/plugins is 0700 root-only\n// after: ensure directory perms\n// chmod 755 /var/run/argo/plugins\n// or in the plugin container spec:\n// securityContext: { runAsUser: 8737 }","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(socketPath); err != nil {\n    if !os.IsNotExist(err) {\n        return fmt.Errorf(\"socket path %q unusable before creating plugin driver: %w\", socketPath, err)\n    }\n} else if dir := filepath.Dir(socketPath); dir != \".\" {\n    if _, err := os.Stat(dir); err != nil || !isSearchable(dir) {\n        return fmt.Errorf(\"socket directory %q not accessible\", dir)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Mount the plugin socket directory as a shared emptyDir with permissive (0755) modes across plugin and executor containers","Keep socket paths short and under standard directories like /var/run/argo to avoid ENAMETOOLONG","Never point socketPath at a location that also holds regular files","Run plugin and executor under the same UID/GID or world-searchable directories"],"tags":["filesystem","unix-socket","permissions","plugin-driver"],"backgroundTag":"unix-socket-stat-failed","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"}