apache/hadoop · error · IOException
%s closed
Error message
%s closed
What it means
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.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/erasurecode/rawcoder/AbstractNativeRawDecoder.java:53
public static Logger LOG =
LoggerFactory.getLogger(AbstractNativeRawDecoder.class);
// Protect ISA-L coder data structure in native layer from being accessed and
// updated concurrently by the init, release and decode functions.
protected final ReentrantReadWriteLock decoderLock =
new ReentrantReadWriteLock();
public AbstractNativeRawDecoder(ErasureCoderOptions coderOptions) {
super(coderOptions);
}
@Override
protected void doDecode(ByteBufferDecodingState decodingState)
throws IOException {
decoderLock.readLock().lock();
try {
if (nativeCoder == 0) {
throw new IOException(String.format("%s closed",
getClass().getSimpleName()));
}
int[] inputOffsets = new int[decodingState.inputs.length];
int[] outputOffsets = new int[decodingState.outputs.length];
ByteBuffer buffer;
for (int i = 0; i < decodingState.inputs.length; ++i) {
buffer = decodingState.inputs[i];
if (buffer != null) {
inputOffsets[i] = buffer.position();
}
}
for (int i = 0; i < decodingState.outputs.length; ++i) {
buffer = decodingState.outputs[i];
outputOffsets[i] = buffer.position();
}
View on GitHub (pinned to 2add963021)
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
Example fix
// before
RawErasureDecoder decoder = CodecUtil.createRawDecoder(conf, "rs", opts);
try (RawErasureDecoder d = decoder) {
d.decode(inputs, erased, outputs);
} // closes the shared instance
decoder.decode(inputs2, erased2, outputs2); // IOException: ... closed
// after
RawErasureDecoder decoder = CodecUtil.createRawDecoder(conf, "rs", opts);
try {
decoder.decode(inputs2, erased2, outputs2);
} finally {
decoder.close();
} Defensive patterns
Strategy: try-catch
Validate before calling
// Track lifecycle yourself: create per workload or pool with invalidation RawErasureDecoder decoder = CodecUtil.createRawDecoder(conf, "rs", opts); // use decoder ... then decoder.close() exactly once at end of workload
Try / catch
try {
decoder.decode(inputs, erased, outputs);
} catch (IOException e) {
if (e.getMessage().endsWith("closed")) {
decoder = CodecUtil.createRawDecoder(conf, "rs", opts); // fresh handle
decoder.decode(inputs, erased, outputs); // retry once
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- %s closed
- %s : %s
- Call cos sdk failed, call method: %s, exception: %s
- listing object '%s' failed.
- Unable to update the boundaries/Range of contentChannel %s
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/e02e5fbae11375bb.
Report an issue: GitHub.