{"record":{"id":"af4c644f7d55874d","repo":"apache/hadoop","slug":"har-completelocaloutput-not-allowed","errorCode":null,"errorMessage":"Har: completeLocalOutput not allowed","messagePattern":"Har: completeLocalOutput not allowed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/HarFileSystem.java","lineNumber":866,"sourceCode":"    FileUtil.copy(this, src, getLocal(getConf()), dst, false, getConf());\n  }\n  \n  /**\n   * not implemented.\n   */\n  @Override\n  public Path startLocalOutput(Path fsOutputFile, Path tmpLocalFile) \n    throws IOException {\n    throw new IOException(\"Har: startLocalOutput not allowed\");\n  }\n  \n  /**\n   * not implemented.\n   */\n  @Override\n  public void completeLocalOutput(Path fsOutputFile, Path tmpLocalFile) \n    throws IOException {\n    throw new IOException(\"Har: completeLocalOutput not allowed\");\n  }\n  \n  /**\n   * not implemented.\n   */\n  @Override\n  public void setOwner(Path p, String username, String groupname)\n    throws IOException {\n    throw new IOException(\"Har: setowner not allowed\");\n  }\n\n  @Override\n  public void setTimes(Path p, long mtime, long atime) throws IOException {\n    throw new IOException(\"Har: setTimes not allowed\");\n  }\n\n  /**\n   * Not implemented.","sourceCodeStart":848,"sourceCodeEnd":884,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/HarFileSystem.java#L848-L884","documentation":"completeLocalOutput(Path fsOutputFile, Path tmpLocalFile) is the commit half of the local-staging protocol: after data is written to the temp file, FileUtil.copy calls it to move the temp into final place. Since staging into a har can never have succeeded (startLocalOutput already throws), reaching this call means custom protocol code is trying to commit into an immutable archive.","triggerScenarios":"Custom implementations of the startLocalOutput/completeLocalOutput dance invoking dstFs.completeLocalOutput(harPath, tmp) — FileUtil.copy itself never gets here because startLocalOutput throws first.","commonSituations":"Hand-rolled large-file upload logic copied from FileSystem/FileUtil internals; wrapper filesystems replaying the staging protocol against an inner HarFileSystem.","solutions":["Replace the manual staging protocol with FileUtil.copy to the underlying HDFS plus `hadoop archive`","If wrapping filesystems, short-circuit the protocol when the destination is read-only","Audit custom copy code for completeLocalOutput calls and add a scheme guard"],"exampleFix":"// before\nPath tmp = dstFs.startLocalOutput(harDst, tmpLocal); // replaced by custom code\nwriteStaged(tmp);\ndstFs.completeLocalOutput(harDst, tmpLocal); // throws: Har: completeLocalOutput not allowed\n\n// after\nFileUtil.copy(localFs, src, hdfs, hdfsDst, false, conf);\n// then: hadoop archive -archiveName data.har -p <dir> <parent>","handlingStrategy":"validation","validationCode":"if (\"har\".equals(fsOutputFile.toUri().getScheme())) {\n  throw new UnsupportedOperationException(\"completeLocalOutput is not supported on har: \" + fsOutputFile);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not reimplement the local-staging commit protocol by hand; use FileUtil.copy against a writable fs","Audit custom copy wrappers for startLocalOutput/completeLocalOutput pairs and guard the destination scheme"],"tags":["hadoop","har-filesystem","read-only","local-output","fileutil-copy"],"backgroundTag":"read-only-filesystem-write","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}