argoproj/argo-workflows · error

failed to open %s: %w

Error message

failed to open %s: %w

What it means

saveParameter failed to open the source parameter file (the script/based output at srcPath) with an error other than not-exist. Notably, os.IsNotExist is deliberately tolerated (parameters may be optional and a warning is logged instead), so reaching this error means the file exists as a path but couldn't be opened — permission denied, EISDIR, or I/O error. The output parameter cannot be saved.

Source

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

		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)

	if common.FindOverlappingVolume(template, srcPath) != nil {
		logger.WithField("src", srcPath).Info(ctx, "no need to save parameter - on overlapping volume")
		return nil
	}
	src, err := os.Open(filepath.Clean(srcPath))
	if os.IsNotExist(err) { // might be optional, so we ignore
		logger.WithField("src", srcPath).WithError(err).Warn(ctx, "cannot save parameter, does not exist")
		return nil
	}
	if err != nil {
		return fmt.Errorf("failed to open %s: %w", srcPath, err)
	}
	defer func() { _ = src.Close() }()
	dstPath := varRunArgo + "/outputs/parameters/" + srcPath
	logger.WithFields(logging.Fields{
		"src": srcPath,
		"dst": dstPath,
	}).Info(ctx, "saving parameter")
	z := filepath.Dir(dstPath)
	if mkdirErr := os.MkdirAll(z, 0o755); mkdirErr != nil { // chmod rwxr-xr-x
		return fmt.Errorf("failed to create directory %s: %w", z, mkdirErr)
	}
	dst, err := os.Create(dstPath)
	if err != nil {
		return fmt.Errorf("failed to create %s: %w", srcPath, err)
	}
	defer func() { _ = dst.Close() }()
	if _, err = io.Copy(dst, src); err != nil {
		return fmt.Errorf("failed to copy %s to %s: %w", srcPath, dstPath, err)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Check the wrapped error: EISDIR means the parameter path must point to a regular file.
  2. chmod/chown the output file so the executor user can read it (e.g. chmod 644 in the script).
  3. If the output may legitimately be absent, keep it optional — missing files already return nil with a warning.
  4. Verify the template's output.parameters[].valueFrom.path is correct and points to a file.

Example fix

// before: script writes as root with 600, argoexec reads as non-root
script:
  source: echo -n hi > /tmp/out; chmod 600 /tmp/out
// after: make it readable
script:
  source: echo -n hi > /tmp/out; chmod 644 /tmp/out
Defensive patterns

Strategy: validation

Validate before calling

// validate parameter source path before it matters
p := tmpl.Outputs.Parameters[0].ValueFrom.Path
fi, err := os.Stat(p)
if err != nil {
    return fmt.Errorf("parameter path %s missing", p) // mark optional if acceptable
}
if fi.IsDir() {
    return fmt.Errorf("parameter path %s is a directory, must be a file", p)
}
if f, err := os.Open(p); err != nil {
    return fmt.Errorf("parameter path %s unreadable: %w", p, err)
} else {
    f.Close()
}

Try / catch

err := runStep(ctx)
if err != nil && strings.Contains(err.Error(), "failed to open") {
    unwrapped := errors.Unwrap(err)
    if errors.Is(unwrapped, syscall.EISDIR) {
        return fixParameterPathToFile(ctx)
    }
    if errors.Is(unwrapped, os.ErrPermission) {
        return fixFilePermissionsAndRetry(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: os.Open(filepath.Clean(srcPath)) returns a non-IsNotExist error: the parameter source path is a directory, the file is unreadable by the argoexec UID, or an I/O error occurs while opening.

Common situations: Template's output parameter path points to a directory instead of a file; script writes output as root but argoexec runs as non-root without read permission; SELinux blocking read; typo making path land on a device/special file.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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