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
- Check the wrapped error: EISDIR means the parameter path must point to a regular file.
- chmod/chown the output file so the executor user can read it (e.g. chmod 644 in the script).
- If the output may legitimately be absent, keep it optional — missing files already return nil with a warning.
- 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
- Point valueFrom.path at a regular file, never a directory
- chmod 644 output files written by other UIDs in the pod
- Treat possibly-absent outputs as optional parameters (missing files are tolerated)
- Lint templates so path typos are caught before runtime
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
- failed to create %s: %w
- failed to copy %s to %s: %w
- stat supervisor status: %w
- failed to open stdout: %w
- failed to open combined: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/ad0d780441aaf667.
Report an issue: GitHub.