{"record":{"id":"5244ad89ba10ed52","repo":"apache/hadoop","slug":"cannot-allocate-block-in-src-passed-previous","errorCode":null,"errorMessage":"Cannot allocate block in <src>: passed 'previous' block <previous> does not match actual last block in file <lastBlockInFile>","messagePattern":"Cannot allocate block in <src>: passed 'previous' block <previous> does not match actual last block in file <lastBlockInFile>","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirWriteFileOp.java","lineNumber":682,"sourceCode":"              \"Request looked like a retry to allocate block \" +\n              lastBlockInFile + \" but it already contains \" +\n              lastBlockInFile.getNumBytes() + \" bytes\");\n        }\n\n        // Case 2\n        // Return the last block.\n        NameNode.stateChangeLog.info(\"BLOCK* allocateBlock: caught retry for \" +\n            \"allocation of a new block in \" + src + \". Returning previously\" +\n            \" allocated block \" + lastBlockInFile);\n        long offset = file.computeFileSize();\n        BlockUnderConstructionFeature uc =\n            lastBlockInFile.getUnderConstructionFeature();\n        onRetryBlock[0] = makeLocatedBlock(fsn, lastBlockInFile,\n            uc.getExpectedStorageLocations(), offset);\n        return new FileState(file, src, iip);\n      } else {\n        // Case 3\n        throw new IOException(\"Cannot allocate block in \" + src + \": \" +\n            \"passed 'previous' block \" + previous + \" does not match actual \" +\n            \"last block in file \" + lastBlockInFile);\n      }\n    }\n    return new FileState(file, src, iip);\n  }\n\n  static boolean completeFile(FSNamesystem fsn, FSPermissionChecker pc,\n      final String srcArg, String holder, ExtendedBlock last, long fileId)\n      throws IOException {\n    String src = srcArg;\n    if (NameNode.stateChangeLog.isDebugEnabled()) {\n      NameNode.stateChangeLog.debug(\"DIR* NameSystem.completeFile: \" +\n                                        src + \" for \" + holder);\n    }\n    checkBlock(fsn, last);\n    INodesInPath iip = fsn.dir.resolvePath(pc, src, fileId);\n    return completeFileInternal(fsn, iip, holder,","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirWriteFileOp.java#L664-L700","documentation":"addBlock requires the client's previous block to match either the completed penultimate block (fresh allocation, case 1) or the penultimate block for a retry (case 2). When it matches neither, the client's view of the file tail and the NameNode's have diverged (another writer appended, lease recovery rebuilt the tail, or state went stale across failover) and case 3 throws IOException.","triggerScenarios":"addBlock(previous=X) where X is neither the current last block nor the penultimate: writing after another client appended under a recovered lease, or a long-lived client using cached block lists after HA failover or lease preemption.","commonSituations":"Two writers on one file after lease steal; custom ClientProtocol clients caching block state; clients surviving NameNode failover without refreshing file state.","solutions":["Close and reopen the writer: fs.append(path) re-reads the authoritative tail, then continue from there","Enforce one writer per file; lease recovery transfers ownership, it does not merge concurrent tails","On HA failover let DFSClient rebuild state instead of caching LocatedBlocks manually"],"exampleFix":"// before: stale cached block drives the next allocation\nnamenode.addBlock(src, clientName, cachedPrevious, fileId, null, 0); // throws\n\n// after: refresh state by reopening for append\ntry (FSDataOutputStream out = fs.append(path)) {\n  out.write(payload);\n}","handlingStrategy":"try-catch","validationCode":"// before allocating the next block, confirm the tail still matches your view\nBlockStatuses tail = namenode.getFileBlockList(src); // custom ClientProtocol only\nif (!matches(previous, tail)) {\n  previous = refreshFrom(tail);\n}","typeGuard":null,"tryCatchPattern":"try {\n  lb = namenode.addBlock(src, clientName, previous, fileId, null, 0);\n} catch (IOException e) { // \"does not match actual last block\"\n  // stale view of the tail: reopen for append and continue\n  try (FSDataOutputStream out = fs.append(path)) {\n    out.write(payload);\n  }\n}","preventionTips":["One writer per file at a time; lease recovery does not merge concurrent tails","After HA failover, reopen streams instead of reusing cached block lists","Custom ClientProtocol clients must refresh file state before addBlock"],"tags":["hdfs","addblock","stale-state","lease-recovery","ha-failover"],"backgroundTag":"stale-block-state","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}