{"record":{"id":"3a30d0e4f7b43c53","repo":"nodejs/node","slug":"unable-to-open-directory-s-n","errorCode":null,"errorMessage":"Unable to open directory: %s\\n","messagePattern":"Unable to open directory: (.+?)\\\\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"deps/icu-small/source/tools/toolutil/filetools.cpp","lineNumber":89,"sourceCode":"                        /* If this new path is a directory, make a recursive call with the newpath. */\n                        closedir(subDirp);\n                        isLatest = isFileModTimeLater(filePath, newpath.data(), isDir);\n                        if (!isLatest) {\n                            break;\n                        }\n                    } else {\n                        int32_t latest = whichFileModTimeIsLater(filePath, newpath.data());\n                        if (latest < 0 || latest == 2) {\n                            isLatest = false;\n                            break;\n                        }\n                    }\n\n                }\n            }\n            closedir(pDir);\n        } else {\n            fprintf(stderr, \"Unable to open directory: %s\\n\", checkAgainst);\n            return false;\n        }\n#endif\n    } else {\n        if (T_FileStream_file_exists(checkAgainst)) {\n            int32_t latest = whichFileModTimeIsLater(filePath, checkAgainst);\n            if (latest < 0 || latest == 2) {\n                isLatest = false;\n            }\n        } else {\n            isLatest = false;\n        }\n    }\n\n    return isLatest;\n}\n\n/* Compares the mod time of both files returning a number indicating which one is later. -1 if error ocurs. */","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/icu-small/source/tools/toolutil/filetools.cpp#L71-L107","documentation":"In isFileModTimeLater, opendir(checkAgainst) returned nullptr so the directory could not be enumerated. The function prints the path and returns false, meaning the target is treated as out-of-date (a rebuild will be forced). The most common errno causes are ENOENT (not found), EACCES (permission), and ENOTDIR (a file, not a directory).","triggerScenarios":"checkAgainst does not exist, is not a directory, or is not readable/searchable by the build user; the directory was removed between a stat and the opendir.","commonSituations":"Stale dependency directories referenced after a clean; permission stripping by packaging; passing a file path where a directory was expected; NFS mount not yet ready.","solutions":["Verify the directory exists and is searchable: ls -ld <path>.","Correct permissions (chmod +rx) so the build user can read and traverse it.","Ensure the argument is a directory, not a file.","Recreate the expected directory if it was deleted by a prior clean step."],"exampleFix":"# before: directory missing or not readable\nopendir('/build/dep') -> NULL\n\n# after: ensure dir exists and is readable\nmkdir -p /build/dep && chmod +rx /build/dep","handlingStrategy":"validation","validationCode":"// Verify checkAgainst is an existing, searchable directory before isFileModTimeLater.\n#include <sys/stat.h>\n#include <unistd.h>\nbool isSearchableDir(const char *p) {\n    struct stat st;\n    return stat(p, &st) == 0 && S_ISDIR(st.st_mode) && access(p, R_OK | X_OK) == 0;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Confirm the directory exists with ls -ld.","Grant read+execute on the directory and parents.","Pass directories, not files, where directories are expected.","Recreate directories removed by a clean step."],"tags":["icu","toolutil","filetools","build-tool","filesystem","permissions"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}