{"record":{"id":"69310fb0d6e5d3bd","repo":"argoproj/argo-workflows","slug":"failed-to-read-working-directory-before-staging-in","errorCode":null,"errorMessage":"failed to read working directory before staging input artifacts: %w","messagePattern":"failed to read working directory before staging input artifacts: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/argoexec/commands/emissary.go","lineNumber":350,"sourceCode":"\treturn common.ResolveTemplateEnvValue(envVal, offloadDir)\n}\n\nfunc stageInputArtifacts(ctx context.Context, tmpl *wfv1.Template) error {\n\treturn stageInputArtifactsAt(ctx, common.ExecutorArtifactBaseDir, tmpl)\n}\n\n// stageInputArtifactsAt is the parameterized form used by tests; production\n// calls stageInputArtifacts with the constants. It links each input artifact\n// into place and re-enters the working directory afterwards, stepping off it\n// for the duration: linking replaces the cwd when an artifact's path is the\n// container's workingDir, Windows refuses to delete a directory in use as a\n// working directory, and a child forked with the deleted directory as cwd\n// would see getcwd() fail and relative paths resolve to nothing. The final\n// chdir follows the symlink to whatever now sits at the path.\nfunc stageInputArtifactsAt(ctx context.Context, baseDir string, tmpl *wfv1.Template) error {\n\torigWd, err := os.Getwd()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read working directory before staging input artifacts: %w\", err)\n\t}\n\tif err := os.Chdir(varRunArgo); err != nil {\n\t\treturn fmt.Errorf(\"failed to leave working directory before staging input artifacts: %w\", err)\n\t}\n\tif err := linkInputArtifactsAt(ctx, baseDir, tmpl); err != nil {\n\t\treturn err\n\t}\n\tif err := os.Chdir(origWd); err != nil {\n\t\treturn fmt.Errorf(\"failed to re-enter working directory %q after staging input artifacts (an input artifact staged at the workingDir path must be a directory): %w\", origWd, err)\n\t}\n\treturn nil\n}\n\n// linkInputArtifactsAt creates a symlink at each input artifact's path\n// pointing to the file that supervisor wrote under /argo/inputs/artifacts/\n// <name>. This replaces the legacy SubPath bind-mount-per-artifact scheme,\n// which can't be used in init-less mode because kubelet pre-creates SubPath\n// entries as empty directories before supervisor can write the real file.","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/cmd/argoexec/commands/emissary.go#L332-L368","documentation":"Before staging (symlinking) input artifacts, the executor records the current working directory via os.Getwd so it can return there afterwards. This error means Getwd itself failed — the process's working directory no longer exists (getcwd() fails on a deleted cwd) or traversal permissions changed. The executor deliberately fails fast here because continuing would leave relative paths unresolvable.","triggerScenarios":"os.Getwd() returns an error inside stageInputArtifactsAt — usually because a parent container process deleted/replaced the working directory (e.g. a previous step rm -rf'ed the mounted dir) before the emissary process staged artifacts, or PWD env is stale and the path cannot be resolved.","commonSituations":"Templates whose workingDir points at a volume mount that a preStep or earlier retry wiped; init-container ordering where the workdir is recreated after argoexec started; k8s subPath mounts deleted and recreated out from under the running pod.","solutions":["Ensure nothing deletes or recreates the template's workingDir directory while the pod runs.","Set an explicit, existing workingDir in the template instead of relying on the image default.","If a previous step must clear the directory, delete contents (rm -rf dir/*) rather than the directory itself.","Check the wrapped inner error (ENOENT vs EACCES) to distinguish deleted cwd from permission problems.","Restart the workflow pod so argoexec starts with a valid cwd."],"exampleFix":"// before\necho done > /dev/null && rm -rf /work   # deletes the pod's cwd\n// after\nrm -rf /work/*   # clear contents, keep the directory","handlingStrategy":"validation","validationCode":"// Ensure the working directory exists before staging:\nstat \"$PWD\" >/dev/null 2>&1 || { echo \"cwd missing\" >&2; exit 1; }","typeGuard":null,"tryCatchPattern":"try {\n  await stageArtifacts(tmpl)\n} catch (e) {\n  if (String(e).includes('failed to read working directory')) {\n    // recreate workingDir and restart the pod\n  }\n}","preventionTips":["Never rm -rf the workingDir itself; delete only its contents.","Set an explicit workingDir that exists in the image.","Avoid steps that recreate mounted directories while the pod is running."],"tags":["kubernetes","argo-workflows","filesystem","working-directory"],"backgroundTag":"deleted-working-directory","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"}