{"record":{"id":"ca4bd351daf3315e","repo":"apache/hadoop","slug":"filesystem-closed","errorCode":null,"errorMessage":"Filesystem closed","messagePattern":"Filesystem closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSClient.java","lineNumber":490,"sourceCode":"   */\n  int getDatanodeWriteTimeout(int numNodes) {\n    final int t = dfsClientConf.getDatanodeSocketWriteTimeout();\n    return t > 0? t + HdfsConstants.WRITE_TIMEOUT_EXTENSION*numNodes: 0;\n  }\n\n  int getDatanodeReadTimeout(int numNodes) {\n    final int t = dfsClientConf.getSocketTimeout();\n    return t > 0? HdfsConstants.READ_TIMEOUT_EXTENSION*numNodes + t: 0;\n  }\n\n  @VisibleForTesting\n  public String getClientName() {\n    return clientName;\n  }\n\n  void checkOpen() throws IOException {\n    if (!clientRunning) {\n      throw new IOException(\"Filesystem closed\");\n    }\n  }\n\n  /** Return the lease renewer instance. The renewer thread won't start\n   *  until the first output stream is created. The same instance will\n   *  be returned until all output streams are closed.\n   */\n  public LeaseRenewer getLeaseRenewer() {\n    return LeaseRenewer.getInstance(\n        namenodeUri != null ? namenodeUri.getAuthority() : \"null\", ugi, this);\n  }\n\n  /** Get a lease and start automatic renewal */\n  private void beginFileLease(final String key, final DFSOutputStream out) {\n    synchronized (filesBeingWritten) {\n      putFileBeingWritten(key, out);\n      LeaseRenewer renewer = getLeaseRenewer();\n      boolean result = renewer.put(this);","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSClient.java#L472-L508","documentation":"DFSClient.checkOpen() guards essentially every client operation: once clientRunning is false (set by DFSClient.close(), which DistributedFileSystem.close() triggers), any subsequent RPC attempt throws IOException('Filesystem closed'). It means the handle is used after its owning FileSystem/DFSClient was closed, often by different code than the failing call.","triggerScenarios":"Calling fs.open()/read()/listStatus()/getFileInfo() after fs.close(); using a DFSInputStream whose parent FileSystem was closed; one thread closing a shared cached FileSystem obtained via FileSystem.get() while another thread still uses the cached instance; UserGroupInformation relogin/logout flows that call FileSystem.closeAllForUGI() invalidating cached handles.","commonSituations":"User code closing a cached FileSystem (FileSystem.get returns the shared cached instance; closing it poisons later get() callers in the same JVM); try-with-resources wrapping a cached FileSystem; MR/Spark tasks whose cleanup closes shared FS handles; long-lived services doing keytab relogin cycles.","solutions":["Pick one ownership model: for FileSystem.get(conf) never call close() (the cache owns it); if you must own closing, create with FileSystem.newInstance(conf) and close exactly once, ideally via try-with-resources.","Fix double-ownership: find the component calling close() on the shared instance (thread dumps, audit code paths around cleanup hooks).","After UGI relogin/logout cycles, drop references and re-acquire FileSystem handles.","As a runtime remedy, catch IOException 'Filesystem closed', discard the reference, get a fresh instance, and retry the operation once."],"exampleFix":"// before\nFileSystem fs = FileSystem.get(conf);\ntry { read(fs); } finally { fs.close(); }\n// poisons the shared cached instance; later FileSystem.get(conf) users get\n// IOException: Filesystem closed\n\n// after (cached, shared - do not close)\nFileSystem fs = FileSystem.get(conf);\nread(fs);\n\n// after (owned instance - close is safe)\ntry (FileSystem fs = FileSystem.newInstance(conf)) {\n  read(fs);\n}","handlingStrategy":"fallback","validationCode":"// no public isOpen(); cheap probe before critical sections\nboolean usable;\ntry { fs.getStatus(); usable = true; }\ncatch (IOException e) { usable = !\"Filesystem closed\".equals(e.getMessage()); }\nif (!usable) { fs = FileSystem.get(conf); /* fresh cached handle */ }","typeGuard":null,"tryCatchPattern":"catch (IOException e) {\n  if (\"Filesystem closed\".equals(e.getMessage())) {\n    fs = FileSystem.newInstance(conf); // or FileSystem.get(conf) after cache invalidation\n    // retry the operation once on the fresh instance\n  } else { throw e; }\n}","preventionTips":["Choose one ownership model per process: cached via FileSystem.get (never close) or owned via newInstance + try-with-resources.","Never put a FileSystem.get() result inside try-with-resources.","Re-acquire FileSystem handles after UGI relogin/logout cycles that call closeAllForUGI."],"tags":["hdfs","filesystem","lifecycle","use-after-close","resource-management","thread-safety"],"backgroundTag":"use-after-close","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}