apache/hadoop · error · IOException

File is not under construction

Error message

File is not under construction: {}

What it means

Replay of OP_CLOSE found the file already complete. For edit logs at or newer than the HDFS-2991 bugfix layout version, a second OP_CLOSE is an error; only pre-0.23.1 logs (HDFS-2991 could log OP_CLOSE twice) are tolerated. The throw means the namespace state and the edit stream disagree about the file.

Solutions

  1. Make fsimage and edit logs in all configured name directories come from the same checkpoint epoch; never mix files from different backups
  2. Run 'hdfs namenode -recover' to skip the inconsistent transaction
  3. Remove duplicated or overlapping segment files and let the NameNode load a clean chain

Example fix

# before: image from backup A mixed with edits from backup B -> duplicate OP_CLOSE
cp backupA/fsimage_* /hadoop/dfs/name/current/ && cp backupB/edits_* /hadoop/dfs/name/current/

# after: restore the whole current/ directory from one backup
rm -rf /hadoop/dfs/name/current && cp -a backupA/current /hadoop/dfs/name/current
Defensive patterns

Strategy: validation

Validate before calling

// image and retained segments must chain with no gap or overlap
NNStorage s = new NNStorage(conf, dirs);
long imgTx = s.getMostRecentCheckpointTxId();
// each segment's [first,last] txid parsed from its filename must start at
// imgTx + 1 and continue contiguously; any duplicate OP_CLOSE candidate
// shows up as an overlapping segment

Try / catch

try {
  loader.loadFSEdits(storage, 0);
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("File is not under construction")) {
    // duplicate OP_CLOSE vs stale image state: restore a single-epoch backup
    // or restart with 'hdfs namenode -recover' to skip it
  }
  throw e;
}

Prevention

When it happens

Trigger: Two OP_CLOSE records for the same file in logs with a post-bugfix layout version; an fsimage that already contains the closed file while edits re-close it; duplicated or mis-ordered segments in the name directories.

Common situations: fsimage restored from one backup and edits from another point in time; duplicate segment files left by a failed manual recovery; rollback or downgrade leaving overlapping transactions.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/e28988c73cc96e57. Report an issue: GitHub.

Appendix: source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSEditLogLoader.java:507

      final INodesInPath iip = fsDir.getINodesInPath(path, DirOp.READ);
      final INodeFile file = INodeFile.valueOf(iip.getLastINode(), path);

      // Update the salient file attributes.
      file.setAccessTime(addCloseOp.atime, Snapshot.CURRENT_STATE_ID, false);
      file.setModificationTime(addCloseOp.mtime, Snapshot.CURRENT_STATE_ID);
      ErasureCodingPolicy ecPolicy =
          FSDirErasureCodingOp.unprotectedGetErasureCodingPolicy(
              fsDir.getFSNamesystem(), iip);
      updateBlocks(fsDir, addCloseOp, iip, file, ecPolicy);

      // Now close the file
      if (!file.isUnderConstruction() &&
          logVersion <= LayoutVersion.BUGFIX_HDFS_2991_VERSION) {
        // There was a bug (HDFS-2991) in hadoop < 0.23.1 where OP_CLOSE
        // could show up twice in a row. But after that version, this
        // should be fixed, so we should treat it as an error.
        throw new IOException(
            "File is not under construction: " + path);
      }
      // One might expect that you could use removeLease(holder, path) here,
      // but OP_CLOSE doesn't serialize the holder. So, remove the inode.
      if (file.isUnderConstruction()) {
        fsNamesys.getLeaseManager().removeLease(file.getId());
        file.toCompleteFile(file.getModificationTime(), 0,
            fsNamesys.getBlockManager().getMinReplication());
      }
      break;
    }
    case OP_APPEND: {
      AppendOp appendOp = (AppendOp) op;
      final String path = renameReservedPathsOnUpgrade(appendOp.path,
          logVersion);
      if (FSNamesystem.LOG.isDebugEnabled()) {
        FSNamesystem.LOG.debug(op.opCode + ": " + path +
            " clientName " + appendOp.clientName +

View on GitHub (pinned to 2add963021)