slimtoolkit/slim · error
cannot open file %q to duplicate app's %s stream: %w
Error message
cannot open file %q to duplicate app's %s stream: %w
What it means
dupAppStdStream creates a log file in artifactsDir (app_<stdout|stderr>.log) to which the app's stream is duplicated. This error is returned when os.OpenFile fails to create/open that file, wrapping the underlying OS error.
Source
Thrown at pkg/app/sensor/monitor/composite.go:356
PtReport: ptReport,
}, nil
}
func NonCriticalError(err error) error {
return fmt.Errorf("non-critical monitor error: %w", err)
}
// Using simple io.MultiWriter(os.Stdout, os.File) would make cmd.Wait()
// block until either the cmd's stdout is closed or the multi-writer is closed.
// However, both are impossible. We need the Wait() to return much earlier
// than the process termination (see pkg/monitors/ptrace logic), and multi-writer
// cannot be closed at all. Hence, the pipe trick.
func dupAppStdStream(artifactsDir string, w io.Writer, kind string) (*os.File, *os.File, error) {
filename := filepath.Join(artifactsDir, "app_"+kind+".log")
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return nil, nil, fmt.Errorf("cannot open file %q to duplicate app's %s stream: %w", filename, kind, err)
}
pr, pw, err := os.Pipe()
if err != nil {
f.Close()
return nil, nil, fmt.Errorf("cannot create pipe for app %s stream: %w", kind, err)
}
go func() {
n, err := io.Copy(io.MultiWriter(w, f), pr)
log.Debugf("dupAppStdStream: io.Copy() finished; written=%d error=%v", n, err)
}()
return pw, f, nil
}
func closeAll(cs []io.Closer) {
for _, c := range cs {View on GitHub (pinned to 81940d17fa)
Solutions
- Ensure the artifacts directory exists and is writable by the user running the sensor (mkdir -p and chown/chmod as needed).
- Check the wrapped OS error for specifics (ENOENT, EACCES, ENOSPC) and fix accordingly.
- Verify there is free disk space and the filesystem is not mounted read-only.
Example fix
// before
NewCompositeMonitor(cfg{ArtifactsDir: "/nonexistent/dir"})
// after
os.MkdirAll("/var/log/artifacts", 0o755)
NewCompositeMonitor(cfg{ArtifactsDir: "/var/log/artifacts"}) Defensive patterns
Strategy: validation
Validate before calling
if info, err := os.Stat(artifactsDir); err != nil || !info.IsDir() {
return fmt.Errorf("artifacts dir %q missing", artifactsDir)
}
probe, err := os.OpenFile(filepath.Join(artifactsDir, ".write_probe"), os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return fmt.Errorf("artifacts dir not writable: %w", err)
}
probe.Close() Try / catch
mon, err := NewCompositeMonitor(cfg)
if err != nil {
if strings.Contains(err.Error(), "cannot open file") {
return fmt.Errorf("check artifacts dir permissions/disk space: %w", err)
}
return err
} Prevention
- Create the artifacts directory with os.MkdirAll and permissive-enough mode before starting monitors.
- Run the sensor with a user that owns or can write the artifacts directory.
- Monitor free disk space on the artifacts volume.
When it happens
Trigger: Calling NewCompositeMonitor when the artifacts directory does not exist, is not writable by the current user, is on a full/read-only filesystem, or the filename is invalid.
Common situations: artifactsDir pointing to a non-existent path or one created with restrictive permissions; running the sensor as a non-root user without write access; disk full; read-only container filesystem.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- failed to set log output destination to %q, touch failed wit
- failed to set log output destination to %q: %w
- cannot create execution - touch event file %q failed: %w
- cannot create execution - open event file %q failed: %w
- invalid context directory
AI-assisted analysis of slimtoolkit/slim@81940d17fa (2026-08-31).
Data as JSON: /api/errors/37345b95cdfa4cde.
Report an issue: GitHub.