apache/cassandra · error · IllegalStateException

Failed to acquire reference to compression dictionary

Error message

Failed to acquire reference to compression dictionary

What it means

When constructing CompressionMetadata for a table using compression dictionaries, buildCloseableArray() must acquire a reference to the dictionary via the dictionary manager. If the ref-counted acquisition returns null (dictionary unavailable/already evicted), the constructor cannot proceed; it closes the chunkOffsets memory first to avoid a leak and throws IllegalStateException.

Source

Thrown at src/java/org/apache/cassandra/io/compress/CompressionMetadata.java:171

        this.compressedFileLength = compressedFileLength;
        this.chunkOffsets = chunkOffsets;
        this.chunkOffsetsSize = chunkOffsetsSize;
        this.compressionDictionary = compressionDictionary;
    }

    private static AutoCloseable[] buildCloseableArray(Memory chunkOffsets, CompressionDictionary dictionary)
    {
        if (dictionary == null)
            return new AutoCloseable[] { chunkOffsets };

        Ref<? extends CompressionDictionary> dictRef = dictionary.tryRef();
        if (dictRef == null)
        {
            // Close chunkOffsets before throwing to prevent resource leak.
            // The CompressionMetadata constructor will not complete if we throw here,
            // so we must clean up resources that were passed in.
            chunkOffsets.close();
            throw new IllegalStateException("Failed to acquire reference to compression dictionary");
        }

        return new AutoCloseable[] { chunkOffsets, dictRef::release };
    }

    /**
     * Copy constructor for creating shared copies via sharedCopy().
     * <br>
     * This uses the WrappedSharedCloseable pattern where all copies share the same
     * underlying resources (chunkOffsets Memory and dictionary reference). The super()
     * call increments the shared reference count, and resources are only released when
     * the last copy is closed.
     * <br>
     * Reference counting behavior:
     * - Original CompressionMetadata acquires 1 dictionary reference (in buildCloseableArray)
     * - All copies share that reference (via super(copy) incrementing shared ref count)
     * - When last copy closes, WrappedSharedCloseable.Tidy releases the reference once
     */

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Restore/keep the compression dictionary files alongside the SSTables when copying or restoring data
  2. Check logs for dictionary manager/eviction errors and restart the node so dictionaries reload
  3. Rewrite the SSTables without dictionaries (disable compression dictionaries for the table, then scrub/upgrade-sstables) if dictionaries are unrecoverable
  4. If constructing metadata in code, close chunkOffsets on failure — or prefer the factory open() paths that handle teardown

Example fix

// before
CompressionMetadata m = new CompressionMetadata(file, len, useMmap); // throws if dict ref null
// after
try {
    CompressionMetadata m = new CompressionMetadata(file, len, useMmap);
} catch (IllegalStateException e) {
    logger.error("Dictionary unavailable for {}", file, e);
    restoreDictionariesOrRewriteSSTable(file);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure dictionary exists before constructing metadata
if (dictionaryManager != null && !dictionaryManager.contains(dictId))
    throw new IllegalStateException("Dictionary missing: " + dictId);

Try / catch

try { return new CompressionMetadata(file, len, useMmap); }
catch (IllegalStateException e) { closeQuietly(chunkOffsets); restoreDictionaryOrRewrite(); throw e; }

Prevention

When it happens

Trigger: Creating CompressionMetadata via the constructor when CompressionDictionaryManager cannot supply an active reference for the dictionary id stored in the metadata — e.g. dictionary file removed, cache shut down, or ref-count lifecycle already released.

Common situations: Dictionary files deleted while SSTables referencing them remain; shutdown race where metadata is opened after dictionary manager closes; mismatched/moved dictionary storage after restoring from backup without the dictionary directory.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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