{"record":{"id":"e02e5fbae11375bb","repo":"apache/hadoop","slug":"s-closed","errorCode":null,"errorMessage":"%s closed","messagePattern":"(.+?) closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/erasurecode/rawcoder/AbstractNativeRawDecoder.java","lineNumber":53,"sourceCode":"  public static Logger LOG =\n      LoggerFactory.getLogger(AbstractNativeRawDecoder.class);\n\n  // Protect ISA-L coder data structure in native layer from being accessed and\n  // updated concurrently by the init, release and decode functions.\n  protected final ReentrantReadWriteLock decoderLock =\n      new ReentrantReadWriteLock();\n\n  public AbstractNativeRawDecoder(ErasureCoderOptions coderOptions) {\n    super(coderOptions);\n  }\n\n  @Override\n  protected void doDecode(ByteBufferDecodingState decodingState)\n      throws IOException {\n    decoderLock.readLock().lock();\n    try {\n      if (nativeCoder == 0) {\n        throw new IOException(String.format(\"%s closed\",\n            getClass().getSimpleName()));\n      }\n      int[] inputOffsets = new int[decodingState.inputs.length];\n      int[] outputOffsets = new int[decodingState.outputs.length];\n\n      ByteBuffer buffer;\n      for (int i = 0; i < decodingState.inputs.length; ++i) {\n        buffer = decodingState.inputs[i];\n        if (buffer != null) {\n          inputOffsets[i] = buffer.position();\n        }\n      }\n\n      for (int i = 0; i < decodingState.outputs.length; ++i) {\n        buffer = decodingState.outputs[i];\n        outputOffsets[i] = buffer.position();\n      }\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/erasurecode/rawcoder/AbstractNativeRawDecoder.java#L35-L71","documentation":"Native raw decoders (ISA-L backed, e.g. NativeRSRawDecoder) hold a long nativeCoder handle to the C-side coder; close()/release() frees it and leaves the field 0. A subsequent doDecode detects nativeCoder == 0 and throws IOException(\"<ClassName> closed\") — a use-after-close on native resources that can no longer serve requests.","triggerScenarios":"Calling decode() on a native RawErasureDecoder after close() was invoked (manually, by another thread, or by try-with-resources scoping); pooling native decoders and closing one on an error path while the pool still hands it out.","commonSituations":"Wrapping a long-lived/pooled coder in try-with-resources so it closes after the first operation; cleanup code that closes shared coders; double close followed by reuse.","solutions":["Do not reuse a native raw decoder after close(); create a fresh one from the RawErasureCoderFactory (e.g., via CodecUtil.createRawDecoder) for the next workload","Scope try-with-resources around each unit of work, or manage a pool that invalidates closed instances and never returns them","Audit error paths that close coders so they also evict the instance from any cache/pool"],"exampleFix":"// before\nRawErasureDecoder decoder = CodecUtil.createRawDecoder(conf, \"rs\", opts);\ntry (RawErasureDecoder d = decoder) {\n  d.decode(inputs, erased, outputs);\n} // closes the shared instance\ndecoder.decode(inputs2, erased2, outputs2); // IOException: ... closed\n\n// after\nRawErasureDecoder decoder = CodecUtil.createRawDecoder(conf, \"rs\", opts);\ntry {\n  decoder.decode(inputs2, erased2, outputs2);\n} finally {\n  decoder.close();\n}","handlingStrategy":"try-catch","validationCode":"// Track lifecycle yourself: create per workload or pool with invalidation\nRawErasureDecoder decoder = CodecUtil.createRawDecoder(conf, \"rs\", opts);\n// use decoder ... then decoder.close() exactly once at end of workload","typeGuard":null,"tryCatchPattern":"try {\n  decoder.decode(inputs, erased, outputs);\n} catch (IOException e) {\n  if (e.getMessage().endsWith(\"closed\")) {\n    decoder = CodecUtil.createRawDecoder(conf, \"rs\", opts); // fresh handle\n    decoder.decode(inputs, erased, outputs); // retry once\n  } else throw e;\n}","preventionTips":["Scope try-with-resources per unit of work, never around a long-lived shared coder","If pooling, evict closed instances on any code path that calls close()","Fail fast in code review on reuse-after-close patterns for native coders"],"tags":["erasure-coding","native","isal","resource-lifecycle","ioexception"],"backgroundTag":"use-after-close","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}