{"record":{"id":"3f4405b2d492c8c6","repo":"denoland/deno","slug":"err-dir-closed","errorCode":"ERR_DIR_CLOSED","errorMessage":"Directory handle was closed","messagePattern":"Directory handle was closed","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_fs/_fs_dir.ts","lineNumber":96,"sourceCode":"              iteratorResult.done\n                ? null\n                : direntFromDeno(iteratorResult.value, this.#dirPath),\n            );\n          }\n        },\n        (err) => {\n          if (callback) {\n            callback(err);\n          }\n          reject(err);\n        },\n      );\n    });\n  }\n\n  readSync(): Dirent | null {\n    if (this.#closed) {\n      throw new ERR_DIR_CLOSED();\n    }\n    if (!this.#syncIterator) {\n      this.#syncIterator = Deno.readDirSync(this.path)![SymbolIterator]();\n    }\n\n    const iteratorResult = ArrayIteratorPrototypeNext(this.#syncIterator);\n    if (iteratorResult.done) {\n      return null;\n    } else {\n      return direntFromDeno(iteratorResult.value, this.#dirPath);\n    }\n  }\n\n  /**\n   * Unlike Node, Deno does not require managing resource ids for reading\n   * directories, and therefore does not need to close directories when\n   * finished reading.\n   */","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/_fs/_fs_dir.ts#L78-L114","documentation":"fs.Dir (returned by fs.opendir) throws ERR_DIR_CLOSED when read()/readSync() is called after close()/closeSync(). The polyfill tracks closure in a private #closed flag; note that unlike Node it does not expose a dir.closed getter, so callers must track the lifecycle themselves.","triggerScenarios":"const d = fs.opendirSync(p); d.closeSync(); d.readSync(); reading in cleanup/finally blocks after the main loop closed the dir; helper functions where one consumer closes and another reads.","commonSituations":"Early-exiting iteration (break) followed by cleanup code that closes, then later code reading again; wrappers whose lifetime differs from their callers; error paths that close the dir and then attempt a final read.","solutions":["Establish a single owner for the Dir and forbid reads after close","Track closed state in your own wrapper and guard every read","Open a fresh fs.opendir when re-iteration is genuinely needed","Prefer for-await...of on the dir, which closes it automatically at completion or break"],"exampleFix":"// before\nconst dir = fs.opendirSync(p);\nlet entry;\nwhile ((entry = dir.readSync())) {\n  if (entry.name === \"stop\") dir.closeSync(); // then read again below\n}\nconst first = dir.readSync(); // ERR_DIR_CLOSED\n\n// after\nconst dir = fs.opendirSync(p);\nlet found = null;\nlet entry;\nwhile ((entry = dir.readSync())) {\n  if (entry.name === \"stop\") { found = entry; break; }\n}\ndir.closeSync();","handlingStrategy":"type-guard","validationCode":"// Node exposes dir.closed; Deno's polyfill does not - track it yourself.\nclass SafeDir {\n  #dir; closed = false;\n  constructor(path: string) { this.#dir = fs.opendirSync(path); }\n  readSync() {\n    if (this.closed) return null; // guard instead of throwing ERR_DIR_CLOSED\n    return this.#dir.readSync();\n  }\n  closeSync() {\n    if (!this.closed) { this.closed = true; this.#dir.closeSync(); }\n  }\n}","typeGuard":"function isOpenDir(d: { closed?: boolean } | null | undefined): boolean {\n  // dir.closed exists on Node; on Deno's polyfill it is undefined, so also\n  // treat 'undefined' as open only if your wrapper tracks closure itself.\n  return d != null && d.closed !== true;\n}","tryCatchPattern":null,"preventionTips":["Give the Dir a single owner; close it exactly once in a finally block","Prefer for-await...of over the dir - it closes automatically on completion or break","Do not read from cleanup/error paths unless you know the dir is still open","Remember the Deno polyfill has no dir.closed getter - track state in a wrapper"],"tags":["fs","node-compat","lifecycle","use-after-close","opendir"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}