{"record":{"id":"7fac2e37dabf2c35","repo":"apache/hadoop","slug":"content-changed-7fac2e","errorCode":null,"errorMessage":"Content changed","messagePattern":"Content changed","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":73,"sourceCode":"    }\n    HdfsPathHandleProto p =\n        HdfsPathHandleProto.parseFrom(ByteString.copyFrom(bytes));\n    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  }","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/HdfsPathHandle.java#L55-L91","documentation":"HdfsPathHandle.verify(stat) throws InvalidPathHandleException('Content changed') when the modification time recorded in the handle differs from the current file's mtime. The handle pins content identity via mtime (and optionally inodeId); an mtime mismatch means the file was written or touched after the handle was created.","triggerScenarios":"FileSystem.open(PathHandle) after the file was appended to, overwritten, or even merely touched (e.g. setTimes, some rename/chown operations updating mtime) between handle creation and open.","commonSituations":"MapReduce/Spark pipelines where a later stage rewrites output in place; tooling that normalizes timestamps after copying; two writers racing on the same path.","solutions":["Write to a new path per generation and hand out fresh handles instead of mutating files referenced by handles.","If the change is expected (benign touch), rebuild the handle from the current status.","Use Option.IO.BYTE_RANGE reads and verify content checksums if partial staleness matters."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Detect mtime drift before opening via handle\nHdfsLocatedFileStatus st = (HdfsLocatedFileStatus) fs.getFileStatus(new Path(handle.getPath()));\n// compare st.getModificationTime() against your recorded mtime; if different, re-mint the handle","typeGuard":null,"tryCatchPattern":"try (FSDataInputStream in = fs.open(handle)) {\n  ...\n} catch (InvalidPathHandleException e) {\n  if (e.getMessage().contains(\"Content changed\")) {\n    // file was modified since handle creation — revalidate or regenerate\n  }\n}","preventionTips":["Treat path-addressed files referenced by handles as immutable; append or write new files instead.","Avoid setTimes/touch on files covered by outstanding handles.","Rebuild handles after any known rewrite of the target file."],"tags":["hdfs","path-handle","staleness","mtime"],"backgroundTag":"stale-file-handle","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}