apache/flink · error · IllegalStateException

segment has been freed

Error message

segment has been freed

What it means

Inside wrapInternal, a segment is detected as freed when address > addressLimit (free() deliberately sets address = addressLimit + 1 to poison it). Calling wrap(offset, length) on a freed segment therefore throws IllegalStateException('segment has been freed') before any ByteBuffer can be created.

Source

Thrown at flink-core/src/main/java/org/apache/flink/core/memory/MemorySegment.java:344

        return wrapInternal(offset, length);
    }

    private ByteBuffer wrapInternal(int offset, int length) {
        if (address <= addressLimit) {
            if (heapMemory != null) {
                return ByteBuffer.wrap(heapMemory, offset, length);
            } else {
                try {
                    ByteBuffer wrapper = Preconditions.checkNotNull(offHeapBuffer).duplicate();
                    wrapper.limit(offset + length);
                    wrapper.position(offset);
                    return wrapper;
                } catch (IllegalArgumentException e) {
                    throw new IndexOutOfBoundsException();
                }
            }
        } else {
            throw new IllegalStateException("segment has been freed");
        }
    }

    /**
     * Gets the owner of this memory segment. Returns null, if the owner was not set.
     *
     * @return The owner of the memory segment, or null, if it does not have an owner.
     */
    @Nullable
    public Object getOwner() {
        return owner;
    }

    // ------------------------------------------------------------------------
    //                    Random Access get() and put() methods
    // ------------------------------------------------------------------------

    // ------------------------------------------------------------------------

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Check segment.isFreed() before wrapping and abort/skip if freed.
  2. Fix ownership so nothing touches a segment after free()/recycle — release cached views before recycling the buffer.
  3. If a ByteBuffer must outlive the segment, copy the bytes into an owned buffer before the segment is freed.

Example fix

// before
ByteBuffer view = segment.wrap(offset, length); // IllegalStateException after free()

// after
if (segment.isFreed()) {
    throw new IllegalStateException("buffer already recycled; copy earlier");
}
ByteBuffer view = segment.wrap(offset, length);
Defensive patterns

Strategy: validation

Validate before calling

if (segment.isFreed()) {
    throw new IllegalStateException("segment already freed; cannot wrap");
}
ByteBuffer view = segment.wrap(offset, length);

Prevention

When it happens

Trigger: Calling wrap() after MemorySegment.free() (or after the owning pool recycled the segment), e.g. retaining a ByteBuffer view beyond the segment's lifetime, or wrapping a buffer that a failed task already released.

Common situations: Caching wrapped ByteBuffers past buffer recycle points in network-stack or sink code; error paths that free segments while other components still hold references; asynchronous writers using a view of memory already returned to the pool.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/85788259cdc8e5ba. Report an issue: GitHub.