apache/cassandra · error · IllegalStateException

Already released

Error message

Already released

What it means

ShareableBytes.doRelease() decrements the reference count; when the count is already 0 (or the RELEASED sentinel) there is nothing to release, indicating an over-release bug, so it throws IllegalStateException. When the count reaches RELEASED the buffer is returned to the networking buffer pool.

Solutions

  1. Audit ownership so exactly one path releases each reference exactly once
  2. Guard with bytes.isReleased() before releasing on error/cleanup paths
  3. Use try-finally so release happens on exactly one well-defined path

Example fix

// before
finally { shared.release(); }  // happy path also released
// after
if (!shared.isReleased()) shared.release();
Defensive patterns

Strategy: validation

Validate before calling

if (!shared.isReleased()) shared.release();

Try / catch

try { shared.release(); } catch (IllegalStateException e) { log.warn("Double release of SharedByteBuffer", e); }

Prevention

When it happens

Trigger: Calling release() more times than retain()/copies of the SharedBytes were handed out, or releasing the same ShareableBytes instance from two paths (e.g. both the frame reader and the consumer).

Common situations: Error-path cleanup that releases a buffer already released in the happy path; double release across async callbacks; connection teardown racing frame consumption.

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/cb74182df56e851b. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/net/ShareableBytes.java:136

            count = this.count;
        }
    }

    public void release()
    {
        owner.doRelease();
    }

    private void doRelease()
    {
        int count = this.count;

        if (count < 0)
            countUpdater.lazySet(this, count += 1);
        else if (count > 0)
            count = countUpdater.decrementAndGet(this);
        else
            throw new IllegalStateException("Already released");

        if (count == RELEASED)
            BufferPools.forNetworking().put(bytes);
    }

    boolean isReleased()
    {
        return owner.count == RELEASED;
    }

    /**
     * Create a slice over the next {@code length} bytes, consuming them from our buffer, and incrementing the owner count
     */
    public ShareableBytes sliceAndConsume(int length)
    {
        int begin = bytes.position();
        int end = begin + length;
        ShareableBytes result = slice(begin, end);

View on GitHub (pinned to 88fd0f6a0e)