argoproj/argo-workflows · error

failed to create directory %s: %w

Error message

failed to create directory %s: %w

What it means

saveArtifact failed to create the parent directory of the artifact destination file under /var/run/argo/outputs/artifacts/ via os.MkdirAll(0o755). The artifact cannot be exported, so the step's output artifact will be missing. The wrapped error reveals the OS cause (usually permissions or disk space).

Source

Thrown at cmd/argoexec/commands/emissary.go:709

func saveArtifact(ctx context.Context, template *wfv1.Template, srcPath string) error {
	logger := logging.RequireLoggerFromContext(ctx)

	if common.FindOverlappingVolume(template, srcPath) != nil {
		logger.WithField("srcPath", srcPath).Info(ctx, "no need to save artifact - on overlapping volume")
		return nil
	}
	if _, err := os.Stat(srcPath); os.IsNotExist(err) { // might be optional, so we ignore
		logger.WithField("srcPath", srcPath).WithError(err).Warn(ctx, "cannot save artifact")
		return nil
	}
	dstPath := filepath.Join(varRunArgo, "/outputs/artifacts/", strings.TrimSuffix(srcPath, "/")+".tgz")
	logger.WithFields(logging.Fields{
		"src": srcPath,
		"dst": dstPath,
	}).Info(ctx, "saving artifact")
	z := filepath.Dir(dstPath)
	if err := os.MkdirAll(z, 0o755); err != nil { // chmod rwxr-xr-x
		return fmt.Errorf("failed to create directory %s: %w", z, err)
	}
	dst, err := os.Create(dstPath)
	if err != nil {
		return fmt.Errorf("failed to create destination %s: %w", dstPath, err)
	}
	defer func() { _ = dst.Close() }()
	if err = archive.TarGzToWriter(ctx, srcPath, gzip.DefaultCompression, dst); err != nil {
		return fmt.Errorf("failed to tarball the output %s to %s: %w", srcPath, dstPath, err)
	}
	if err = dst.Close(); err != nil {
		return fmt.Errorf("failed to close %s: %w", dstPath, err)
	}
	return nil
}

func saveParameter(ctx context.Context, template *wfv1.Template, srcPath string) error {
	logger := logging.RequireLoggerFromContext(ctx)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Read the wrapped error: EEXIST/ENOTDIR means a file occupies a directory component of the artifact path — rename the template's artifact path.
  2. Free node disk space if ENOSPC.
  3. Grant the container write access to /var/run/argo (volume mount, correct runAsUser, not read-only).
  4. Verify the artifact path in the template is a valid directory-form path (path.Dir is computed on it).

Example fix

// before: template artifact path that collides with a file
outputs:
  artifacts:
  - name: out
    path: /tmp/result        # /tmp/result is a FILE being both source base and dir component
// after: use a dedicated output directory path
outputs:
  artifacts:
  - name: out
    path: /tmp/results/output.tgz
Defensive patterns

Strategy: validation

Validate before calling

// validate template artifact paths before submit
for _, art := range tmpl.Outputs.Artifacts {
    if strings.HasSuffix(art.Path, "/") || art.Path == "" {
        return fmt.Errorf("artifact %q path %q invalid", art.Name, art.Path)
    }
}
// ensure /var/run/argo/outputs is writable in the image
// os.MkdirAll("/var/run/argo/outputs/artifacts", 0o755)

Try / catch

if err := runStep(ctx); err != nil {
    var wrapped error
    if errors.Unwrap(err) != nil {
        wrapped = errors.Unwrap(err)
    }
    if errors.Is(wrapped, os.ErrExist) || errors.Is(wrapped, syscall.ENOTDIR) {
        return fixArtifactPathAndResubmit(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll(filepath.Dir(dstPath), 0o755) fails while saving an output artifact: /var/run/argo/outputs is not writable, disk is full, or a non-directory file exists at a path component of dstPath (path derived from the template's artifact path).

Common situations: Templates whose output artifact path collides with an existing file (e.g. path /var/run/argo/outputs/artifacts/foo where foo is a file); readOnlyRootFilesystem pods; ENOSPC; runAsUser without write access to /var/run/argo.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/1d5b901a29ffa1d0. Report an issue: GitHub.