{"record":{"id":"d8716786f9fb60b9","repo":"slimtoolkit/slim","slug":"non-critical-monitor-error-w","errorCode":null,"errorMessage":"non-critical monitor error: %w","messagePattern":"non-critical monitor error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/app/sensor/monitor/composite.go","lineNumber":343,"sourceCode":"\tfanReport, fanErr := m.fanMon.Status()\n\tptReport, ptErr := m.ptMon.Status()\n\n\tif fanErr != nil || ptErr != nil {\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"one or more monitors failed: fanotify.error=%q, ptrace.error=%q\",\n\t\t\tfanErr, ptErr,\n\t\t)\n\t}\n\n\treturn &CompositeReport{\n\t\t// PeReport: peReport,\n\t\tFanReport: fanReport,\n\t\tPtReport:  ptReport,\n\t}, nil\n}\n\nfunc NonCriticalError(err error) error {\n\treturn fmt.Errorf(\"non-critical monitor error: %w\", err)\n}\n\n// Using simple io.MultiWriter(os.Stdout, os.File) would make cmd.Wait()\n// block until either the cmd's stdout is closed or the multi-writer is closed.\n// However, both are impossible. We need the Wait() to return much earlier\n// than the process termination (see pkg/monitors/ptrace logic), and multi-writer\n// cannot be closed at all. Hence, the pipe trick.\nfunc dupAppStdStream(artifactsDir string, w io.Writer, kind string) (*os.File, *os.File, error) {\n\tfilename := filepath.Join(artifactsDir, \"app_\"+kind+\".log\")\n\n\tf, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"cannot open file %q to duplicate app's %s stream: %w\", filename, kind, err)\n\t}\n\n\tpr, pw, err := os.Pipe()\n\tif err != nil {\n\t\tf.Close()","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/slimtoolkit/slim/blob/81940d17fa112cc678e32209214bcb2355cb3004/pkg/app/sensor/monitor/composite.go#L325-L361","documentation":"NonCriticalError wraps an error to mark it as non-fatal for the monitoring pipeline. Callers (runWithMonitor, processMonitoringResults, runMonitor) use it to classify monitor failures that should be logged but must not abort the whole sensor run.","triggerScenarios":"Any code path that wraps a monitor error with NonCriticalError(err) — e.g. a sub-monitor (fanotify or ptrace) failing during a run where its failure is tolerable.","commonSituations":"fanotify unavailable on the container's filesystem/kernel; ptrace blocked by seccomp/AppArmor; target app exiting early — these get wrapped as non-critical so the scan continues.","solutions":["Inspect the wrapped error (%w) via errors.Unwrap or errors.As to find the root cause.","If the failure should be fatal, change the classification at the call site instead of treating it as non-critical.","Fix the underlying monitor issue (privileges, kernel support) to eliminate the warning."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func asNonCritical(err error) (error, bool) {\n    // the wrapper is textual; inspect the message or match on the wrapped cause\n    if err == nil {\n        return nil, false\n    }\n    return errors.Unwrap(err), strings.Contains(err.Error(), \"non-critical monitor error\")\n}","tryCatchPattern":"if err := runMonitor(ctx, m); err != nil {\n    if _, nonCritical := asNonCritical(err); nonCritical {\n        log.Warnf(\"continuing despite monitor issue: %v\", err)\n    } else {\n        return err\n    }\n}","preventionTips":["Treat non-critical monitor errors as degraded-mode signals and log them with context.","Use a sentinel wrapper type instead of matching message text where possible.","Fix root causes (privileges, kernel features) to reduce non-critical failures in production."],"tags":["monitoring","error-wrapping","fault-tolerance"],"backgroundTag":"non-critical-monitor-failure","analyzedSha":"81940d17fa112cc678e32209214bcb2355cb3004","analyzedAt":"2026-08-31T23:06:12.682Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}