apache/cassandra · error · IllegalStateException

Cannot create a sharedCopy of a SafeMemory object that has…

Error message

Cannot create a sharedCopy of a SafeMemory object that has already been closed

What it means

SafeMemory's copy constructor calls ref.ensureReleased() when the copy's peer pointer is null but the size is non-zero, meaning the source SafeMemory was already closed (its native memory freed). It throws IllegalStateException to prevent handing out a shared copy of freed off-heap memory. Accessing such memory would otherwise crash the JVM.

Solutions

  1. Ensure the source SafeMemory is still open before calling sharedCopy(); restructure ownership so closer is the last user
  2. Call sharedCopy() before the source is closed and manage the copy's lifecycle independently
  3. Wrap shared copies in try-with-resources and avoid closing shared copies while other copies are live
  4. Use ref-counted access (the ref() handle) to coordinate close across threads

Example fix

// before
try (SafeMemory mem = acquire()) { sharedHolder.set(mem); } // closed on exit
SafeMemory copy = sharedHolder.get().sharedCopy(); // throws
// after
try (SafeMemory mem = acquire()) { sharedHolder.set(mem.sharedCopy()); }
SafeMemory copy = sharedHolder.get().sharedCopy(); // valid
Defensive patterns

Strategy: try-catch

Validate before calling

if (source.isClosed()) throw new IllegalStateException("source already closed"); // or track open state yourself

Type guard

boolean usable(SafeMemory m) { return m != null && !m.isClosed(); }

Try / catch

try { SafeMemory copy = mem.sharedCopy(); } catch (IllegalStateException e) { /* recreate source or skip */ }

Prevention

When it happens

Trigger: Calling new SafeMemory(existing) or existing.sharedCopy() after the source SafeMemory has been closed via close() (or try-with-resources exiting its scope).

Common situations: Sharing a SafeMemory across threads where one thread closes it while another still holds a reference; use-after-close in try-with-resources; keeping a copy of a Rebuffer/Memory-managed buffer beyond its owner's lifetime.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/ae4c7e910f9995ba. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/io/util/SafeMemory.java:45

public class SafeMemory extends Memory implements SharedCloseable
{
    private final Ref<?> ref;
    public SafeMemory(long size)
    {
        super(size);
        ref = new Ref<>(null, new MemoryTidy(peer, size));
    }

    private SafeMemory(SafeMemory copyOf)
    {
        super(copyOf);
        ref = copyOf.ref.ref();
        /** see {@link Memory#Memory(long)} re: null pointers*/
        if (peer == 0 && size != 0)
        {
            ref.ensureReleased();
            throw new IllegalStateException("Cannot create a sharedCopy of a SafeMemory object that has already been closed");
        }
    }

    public SafeMemory sharedCopy()
    {
        return new SafeMemory(this);
    }

    public void free()
    {
        ref.release();
        peer = 0;
    }

    public void close()
    {
        ref.ensureReleased();
        peer = 0;

View on GitHub (pinned to 88fd0f6a0e)