{"record":{"id":"9d71f35dcdc16675","repo":"cloudflare/cloudflared","slug":"error-opening-file-s-w-9d71f3","errorCode":null,"errorMessage":"error opening file %s:%w","messagePattern":"error opening file (.+?):%w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"diagnostic/log_collector_utils.go","lineNumber":103,"sourceCode":"\tdefer func() { _ = outputHandle.Close() }()\n\n\tfor _, file := range files {\n\t\t// nolint: gosec\n\t\tlogHandle, err := os.Open(filepath.Join(path, file.Name()))\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error opening file %s: %w\", file.Name(), err)\n\t\t}\n\t\t_, err = io.Copy(outputHandle, logHandle)\n\t\t_ = logHandle.Close()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error copying file %s: %w\", file.Name(), err)\n\t\t}\n\t}\n\n\t// nolint: gosec\n\tlogHandle, err := os.Open(filepath.Join(path, defaultLogFilename))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error opening file %s:%w\", defaultLogFilename, err)\n\t}\n\tdefer func() { _ = logHandle.Close() }()\n\n\t_, err = io.Copy(outputHandle, logHandle)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"error copying file %s:%w\", logHandle.Name(), err)\n\t}\n\n\treturn outputHandle.Name(), nil\n}\n","sourceCodeStart":85,"sourceCodeEnd":114,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/diagnostic/log_collector_utils.go#L85-L114","documentation":"CopyFilesFromDirectory in the diagnostic package tries to open the tunnel's default log file (cloudflared.log) inside the given directory to copy it into a diagnostic bundle. When os.Open fails, it wraps the underlying OS error (ENOENT, EACCES, etc.) with this message and returns an empty path, aborting log collection. It reflects that the log file could not be read from disk.","triggerScenarios":"Calling CopyFilesFromDirectory (directly or via collectLogs) when the log file does not exist at filepath.Join(path, defaultLogFilename), the path points to a directory without the expected file, or the file lacks read permission.","commonSituations":"Diagnostic collection on a system where cloudflared was never run with logging enabled; log directory rotated/deleted before collection; running under a service account that cannot read the log directory (e.g. /var/log/cloudflared owned by root); SELinux/AppArmor denials.","solutions":["Verify the log file exists at the expected path before collecting: os.Stat(filepath.Join(path, defaultLogFilename)).","Check file permissions and ownership; run collection as a user that can read the log directory (or adjust ACLs/SELinux context).","Pass the correct directory path containing the log file to CopyFilesFromDirectory.","Handle the wrapped *fs.PathError in the caller to distinguish not-found from permission issues."],"exampleFix":"// before\nout, err := CopyFilesFromDirectory(ctx, logDir)\nif err != nil {\n\treturn err\n}\n// after\nlogPath := filepath.Join(logDir, diagnostic.DefaultLogFilename)\nif _, err := os.Stat(logPath); errors.Is(err, fs.ErrNotExist) {\n\t// skip log collection, no log file present\n\treturn nil\n}\nout, err := CopyFilesFromDirectory(ctx, logDir)\nif err != nil {\n\treturn fmt.Errorf(\"collect logs: %w\", err)\n}","handlingStrategy":"validation","validationCode":"logPath := filepath.Join(dir, \"cloudflared.log\")\nif _, err := os.Stat(logPath); err != nil {\n\tif errors.Is(err, fs.ErrNotExist) { /* skip collection */ }\n\tif errors.Is(err, fs.ErrPermission) { /* fix perms or run as root */ }\n}","typeGuard":"func logFileReadable(dir, name string) bool {\n\tf, err := os.Open(filepath.Join(dir, name))\n\tif err != nil { return false }\n\t_ = f.Close()\n\treturn true\n}","tryCatchPattern":"out, err := CopyFilesFromDirectory(ctx, dir)\nvar pe *fs.PathError\nif errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrNotExist) {\n\t// degrade gracefully: proceed without log file\n}","preventionTips":["Stat the log file before invoking collection","Run diagnostic collection under an account with read access to the log directory","Confirm logging was enabled in the tunnel run so the file exists","Watch for SELinux/AppArmor denials in audit logs"],"tags":["diagnostics","filesystem","go"],"backgroundTag":"file-open-failed","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}