{"record":{"id":"d860bb099f9e64c0","repo":"argoproj/argo-workflows","slug":"mkdir-s-w","errorCode":null,"errorMessage":"mkdir %s: %w","messagePattern":"mkdir (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/artifacts/gcs/gcs.go","lineNumber":163,"sourceCode":"\t}\n\tfor _, objName := range objNames {\n\t\terr = downloadObject(ctx, client, bucket, key, objName, path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// download an object from the bucket\nfunc downloadObject(ctx context.Context, client *storage.Client, bucket, key, objName, path string) error {\n\tobjPrefix := normalizeGCSKey(filepath.Clean(key))\n\trelObjPath := strings.TrimPrefix(objName, objPrefix)\n\tlocalPath := filepath.Join(path, relObjPath)\n\tobjectDir, _ := filepath.Split(localPath)\n\tif objectDir != \"\" {\n\t\tif err := os.MkdirAll(objectDir, 0o700); err != nil {\n\t\t\treturn fmt.Errorf(\"mkdir %s: %w\", objectDir, err)\n\t\t}\n\t}\n\trc, err := client.Bucket(bucket).Object(objName).NewReader(ctx)\n\tif err != nil {\n\t\tif errors.Is(err, storage.ErrObjectNotExist) {\n\t\t\treturn argoerrors.New(argoerrors.CodeNotFound, err.Error())\n\t\t}\n\t\treturn fmt.Errorf(\"new bucket reader: %w\", err)\n\t}\n\tdefer rc.Close()\n\tout, err := os.Create(localPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"os create %s: %w\", localPath, err)\n\t}\n\tdefer func() {\n\t\tif closeErr := out.Close(); closeErr != nil {\n\t\t\tlogger := logging.RequireLoggerFromContext(ctx)\n\t\t\tlogger.WithField(\"path\", localPath).WithError(closeErr).Error(ctx, \"Error closing file\")","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/artifacts/gcs/gcs.go#L145-L181","documentation":"When downloading a GCS object (or a directory-expanded set of objects), downloadObject computes the local path and creates parent directories with os.MkdirAll(objectDir, 0o700) before writing. This error wraps a failure of that mkdir. It indicates the local artifact destination directory tree could not be created.","triggerScenarios":"os.MkdirAll fails while preparing the target path for an artifact download: parent path component exists as a regular file, permission denied on the output mount, path too long, or read-only filesystem.","commonSituations":"Artifact path collides with an existing file of the same name; output volume mounted read-only; non-root container lacking write permission to the path; NFS/emptyDir I/O errors.","solutions":["Check no file exists at the target directory path and use a distinct artifact path","Make the output volume writable by the container user (securityContext fsGroup / chmod)","Verify the volume is not mounted read-only in the pod spec","Check disk and filesystem health on the node"],"exampleFix":"// before: path collides with an existing file\nartifacts: [{name: out, path: /mnt/out}]\n// /mnt/out exists as a FILE\n// after\nartifacts: [{name: out, path: /mnt/artifacts/out}]  // unique directory path","handlingStrategy":"validation","validationCode":"import \"os\"\nfunc ensureArtifactDirWritable(path string) error {\n\tif fi, err := os.Stat(path); err == nil && !fi.IsDir() {\n\t\treturn fmt.Errorf(\"%s exists as a file\", path)\n\t}\n\tprobe := filepath.Join(path, \".argo-write-probe\")\n\tif err := os.MkdirAll(filepath.Dir(probe), 0o700); err != nil { return err }\n\treturn os.Remove(probe)\n}","typeGuard":null,"tryCatchPattern":"if err := downloadArtifacts(ctx); err != nil {\n\tif strings.Contains(err.Error(), \"mkdir \") && os.IsPermission(errors.Unwrap(err)) {\n\t\t// fix volume permissions/fsGroup, then retry\n\t}\n\treturn err\n}","preventionTips":["Give each artifact a unique directory path to avoid file/dir collisions","Set securityContext.fsGroup to match volume ownership","Never mount output volumes readOnly for steps that save artifacts"],"tags":["filesystem","mkdir","gcs","artifacts"],"backgroundTag":"mkdir-permission-denied","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"}