{"record":{"id":"7537239496f5d4d8","repo":"apache/hadoop","slug":"wrong-file","errorCode":null,"errorMessage":"Wrong file","messagePattern":"Wrong file","errorType":"exception","errorClass":"InvalidPathHandleException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/HdfsPathHandle.java","lineNumber":76,"sourceCode":"    path = p.getPath();\n    mtime   = p.hasMtime()   ? p.getMtime()   : null;\n    inodeId = p.hasInodeId() ? p.getInodeId() : null;\n  }\n\n  public String getPath() {\n    return path;\n  }\n\n  public void verify(HdfsLocatedFileStatus stat)\n      throws InvalidPathHandleException {\n    if (null == stat) {\n      throw new InvalidPathHandleException(\"Could not resolve handle\");\n    }\n    if (mtime != null && mtime != stat.getModificationTime()) {\n      throw new InvalidPathHandleException(\"Content changed\");\n    }\n    if (inodeId != null && inodeId != stat.getFileId()) {\n      throw new InvalidPathHandleException(\"Wrong file\");\n    }\n  }\n\n  @Override\n  public ByteBuffer bytes() {\n    HdfsPathHandleProto.Builder b = HdfsPathHandleProto.newBuilder();\n    b.setPath(path);\n    if (inodeId != null) {\n      b.setInodeId(inodeId);\n    }\n    if (mtime != null) {\n      b.setMtime(mtime);\n    }\n    return b.build().toByteString().asReadOnlyByteBuffer();\n  }\n\n  @Override\n  public boolean equals(Object other) {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/HdfsPathHandle.java#L58-L94","documentation":"HdfsPathHandle.verify(stat) throws InvalidPathHandleException('Wrong file') when the inodeId embedded in the handle differs from the resolved file's inodeId. Same path but different inode means the file was deleted and re-created (new inode), so the handle's identity no longer matches even if mtime coincidentally does.","triggerScenarios":"open(PathHandle) after the target file was removed and recreated at the same path (common with atomic 'write temp + rename' pipelines that replace output), or after truncate-like operations that cycle inodes.","commonSituations":"Job dedup workflows that delete-then-rewrite output; snapshot restore that recreates inodes; handles persisted across such operations.","solutions":["Treat the handle as invalid: re-resolve the path and mint a new PathHandle.","Design writers to create new paths (or use append) rather than delete+recreate files that others hold handles to.","Persist the source generation id along with the handle so consumers can detect lineage resets."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify inode identity before opening via handle\nHdfsLocatedFileStatus st = (HdfsLocatedFileStatus) fs.getFileStatus(new Path(handle.getPath()));\n// if st.getFileId() != your recorded inodeId, the file was replaced — re-mint the handle","typeGuard":null,"tryCatchPattern":"try (FSDataInputStream in = fs.open(handle)) {\n  ...\n} catch (InvalidPathHandleException e) {\n  if (e.getMessage().contains(\"Wrong file\")) {\n    // inode replaced at same path — regenerate the handle from the current file\n  }\n}","preventionTips":["Avoid delete+recreate cycles on paths that carry handles; use rename-over or versioned paths.","Record inodeId alongside handles in job metadata for quick drift detection.","After restores/migrations, always regenerate handles since inode ids change."],"tags":["hdfs","path-handle","identity","inode"],"backgroundTag":"stale-file-handle","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}