{"record":{"id":"c7220cd41af5e5b1","repo":"argoproj/argo-workflows","slug":"failed-to-symlink-input-artifact-q-s-s-w","errorCode":null,"errorMessage":"failed to symlink input artifact %q (%s -> %s): %w","messagePattern":"failed to symlink input artifact %q \\((.+?) -> (.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/argoexec/commands/emissary.go","lineNumber":438,"sourceCode":"\t\t\t// mounts (tmpfs /run, the overlay rootfs) are not declared user volumes\n\t\t\t// and so remain safe to shadow.\n\t\t\trealParent, evalErr := filepath.EvalSymlinks(filepath.Dir(dst))\n\t\t\tif evalErr != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to resolve parent of artifact path %q at %s: %w\", art.Name, dst, evalErr)\n\t\t\t}\n\t\t\tresolved := filepath.Join(realParent, filepath.Base(dst))\n\t\t\tif mnt := common.FindOverlappingVolume(tmpl, resolved); mnt != nil {\n\t\t\t\treturn fmt.Errorf(\"refusing to stage input artifact %q at %s: it resolves to %s inside volume mount %q (%s), and clearing it would destroy the mounted volume; change the artifact path or volume mount so they do not overlap\", art.Name, dst, resolved, mnt.Name, mnt.MountPath)\n\t\t\t}\n\t\t\tif mnt := common.FindVolumeMountNestedUnderPath(tmpl, resolved); mnt != nil {\n\t\t\t\treturn fmt.Errorf(\"refusing to stage input artifact %q at %s: it resolves to %s which contains volume mount %q (%s), and clearing it would destroy the mounted volume; change the artifact path or volume mount so they do not overlap\", art.Name, dst, resolved, mnt.Name, mnt.MountPath)\n\t\t\t}\n\t\t\tif rmErr := os.RemoveAll(dst); rmErr != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to clear existing path for artifact %q at %s: %w\", art.Name, dst, rmErr)\n\t\t\t}\n\t\t}\n\t\tif err := os.Symlink(src, dst); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to symlink input artifact %q (%s -> %s): %w\", art.Name, dst, src, err)\n\t\t}\n\t\tlogger.WithFields(logging.Fields{\"name\": art.Name, \"src\": src, \"dst\": dst}).Debug(ctx, \"linked input artifact\")\n\t}\n\treturn nil\n}\n\n// waitForSupervisorReady blocks until the supervisor's status marker reports a\n// terminal outcome (READY/FAILED), or until the supervisor is presumed dead.\n// Used only in init-less pod mode where main and supervisor start concurrently.\n// VarRunArgoPath itself is guaranteed to exist because the emissary has\n// already created /var/run/argo/ctr/<name> earlier in main, which MkdirAll'd\n// the full parent chain.\nfunc waitForSupervisorReady(ctx context.Context) error {\n\treturn waitForSupervisorReadyAt(ctx, common.StatusMarkerPath, supervisorHeartbeatTimeout, supervisorStatusPollInterval)\n}\n\n// waitForSupervisorReadyAt is the parameterized form used by tests; production\n// calls waitForSupervisorReady with the constants.","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/cmd/argoexec/commands/emissary.go#L420-L456","documentation":"After clearing (or confirming absence of) the destination, argoexec creates the symlink src -> dst for the input artifact. If os.Symlink fails, this wrapped error is returned. It usually wraps EEXIST (a path component raced or the clear was skipped) or permission/errno errors on the parent directory.","triggerScenarios":"os.Symlink(src, dst) errors during linkInputArtifactsAt: dst reappeared between RemoveAll and Symlink, the parent is not writable, or dst sits on a filesystem that does not support symlinks (e.g. some network filesystems).","commonSituations":"Non-root container writing to a root-owned directory; FAT/exFAT or certain fuse/network mounts lacking symlink support; concurrent processes recreating the destination path; SELinux/AppArmor denial.","solutions":["Check the wrapped errno in the full error for the precise cause (EEXIST vs EACCES vs EPERM)","Ensure the parent directory of `path` is writable by the container user or run with a securityContext granting write access","Pick a destination on a symlink-capable filesystem (emptyDir, overlayfs)","Avoid concurrent writers to the same artifact path within the container"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Ensure destination parent is writable and filesystem supports symlinks:\n# in an init/debug step:\ntest -w \"$(dirname /tmp/app/config.yaml)\" || echo \"parent not writable\"\nmkdir -p /tmp/app && ln -s /tmp/probe /tmp/app/.probe 2>&1 || echo \"symlinks unsupported\"","typeGuard":null,"tryCatchPattern":"err := linkInputArtifacts(ctx, tmpl)\nif err != nil {\n    var perr *os.LinkError\n    if errors.As(err, &perr) {\n        log.Printf(\"symlink failed op=%q old=%q new=%q err=%v\", perr.Op, perr.Old, perr.New, perr.Err)\n        // EACCES -> fix permissions; EEXIST -> concurrent writer; EPERM -> fs lacks symlink support\n    }\n    return err\n}","preventionTips":["Run containers with a user that owns the destination directory","Avoid FAT/exFAT or fuse/network mounts as artifact destinations","Don't run concurrent processes that touch the same artifact path","Check the wrapped errno in the error message to pick the right fix"],"tags":["kubernetes","argo-workflows","artifacts","symlink","permissions"],"backgroundTag":"symlink-creation-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"}