{"record":{"id":"316e9dfabd8d7b16","repo":"juanfont/headscale","slug":"reading-logs-directory-w","errorCode":null,"errorMessage":"reading logs directory: %w","messagePattern":"reading logs directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/hi/cleanup.go","lineNumber":342,"sourceCode":"\t\tfmt.Printf(\"Removed Go module cache volume: %s\\n\", volumeName)\n\t}\n\n\treturn nil\n}\n\n// cleanupSuccessfulTestArtifacts removes artifacts from successful test runs to save disk space.\n// This function removes large artifacts that are mainly useful for debugging failures:\n// - Database dumps (.db files)\n// - Profile data (pprof directories)\n// - MapResponse data (mapresponses directories)\n// - Prometheus metrics files\n//\n// It preserves:\n// - Log files (.log) which are small and useful for verification.\nfunc cleanupSuccessfulTestArtifacts(logsDir string, verbose bool) error {\n\tentries, err := os.ReadDir(logsDir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading logs directory: %w\", err)\n\t}\n\n\tvar (\n\t\tremovedFiles, removedDirs int\n\t\ttotalSize                 int64\n\t)\n\n\tfor _, entry := range entries {\n\t\tname := entry.Name()\n\t\tfullPath := filepath.Join(logsDir, name)\n\n\t\tif entry.IsDir() {\n\t\t\t// Remove pprof and mapresponses directories (typically large)\n\t\t\t// These directories contain artifacts from all containers in the test run\n\t\t\tif name == \"pprof\" || name == \"mapresponses\" {\n\t\t\t\tsize, sizeErr := getDirSize(fullPath)\n\t\t\t\tif sizeErr == nil {\n\t\t\t\t\ttotalSize += size","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/hi/cleanup.go#L324-L360","documentation":"Returned by cleanupSuccessfulTestArtifacts when os.ReadDir on the control_logs directory fails. Filesystem-level causes: the directory does not exist (no runs recorded yet), permission denied, or the path is not a directory. It propagates from `hi cleanup` when pruning artifacts of successful runs.","triggerScenarios":"Running artifact cleanup when the logs directory was deleted or never created (no prior test runs); insufficient permissions on control_logs; a file existing where the directory is expected.","commonSituations":"Fresh checkouts before any integration run; CI workspaces wiped between jobs; directories removed by disk-cleanup scripts; ownership mismatches after running tests as root and cleaning as user.","solutions":["Check that the logs directory exists and is readable: ls control_logs/","Create it or run one integration test first so it gets populated","Fix ownership/permissions (chown/chmod) if tests ran as another user","Remove blocking non-directory entries at the expected path"],"exampleFix":"# before: no runs yet, directory absent\ngo run ./cmd/hi cleanup   # reading logs directory: ...\n\n# after\nmkdir -p control_logs\ngo run ./cmd/hi cleanup","handlingStrategy":"validation","validationCode":"// Ensure the logs dir exists and is a directory before cleanup.\nif fi, err := os.Stat(logsDir); err != nil {\n\tfmt.Fprintln(os.Stderr, \"no logs directory yet — nothing to clean\")\n\treturn nil\n} else if !fi.IsDir() {\n\treturn fmt.Errorf(\"%s is not a directory\", logsDir)\n}","typeGuard":"func isReadableDir(path string) bool {\n\tfi, err := os.Stat(path)\n\treturn err == nil && fi.IsDir()\n}","tryCatchPattern":"Treat os.IsNotExist(err) from ReadDir as a no-op (nothing to clean); other errors (permission) should be reported with the path.","preventionTips":["Create control_logs/ as part of workspace setup","Keep ownership consistent — avoid mixing sudo and user-run tests","Run at least one integration test before expecting cleanup to find artifacts"],"tags":["filesystem","cleanup","logs","hi"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}