{"record":{"id":"e20358419aba41ea","repo":"apache/cassandra","slug":"failed-to-save-bloom-filter-for-sstable","errorCode":null,"errorMessage":"Failed to save Bloom filter for SSTable: ","messagePattern":"Failed to save Bloom filter for SSTable: ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/sstable/format/FilterComponent.java","lineNumber":86,"sourceCode":"        {\n            throw new IOException(\"Failed to load Bloom filter for SSTable: \" + descriptor.baseFile(), ex);\n        }\n    }\n\n    public static void save(IFilter filter, Descriptor descriptor, boolean deleteOnFailure) throws IOException\n    {\n        File filterFile = descriptor.fileFor(Components.FILTER);\n        try (FileOutputStreamPlus stream = filterFile.newOutputStream(File.WriteMode.OVERWRITE))\n        {\n            filter.serialize(stream, descriptor.version.hasOldBfFormat());\n            stream.flush();\n            stream.sync();\n        }\n        catch (IOException ex)\n        {\n            if (deleteOnFailure)\n                descriptor.fileFor(Components.FILTER).deleteIfExists();\n            throw new IOException(\"Failed to save Bloom filter for SSTable: \" + descriptor.baseFile(), ex);\n        }\n    }\n\n    /**\n     * Optionally loads a Bloom filter.\n     * If the filter is not needed (FP chance is neglectable), it returns {@link FilterFactory#AlwaysPresent}.\n     * If the filter is expected to be recreated for various reasons the method returns {@code null}.\n     * Otherwise, an attempt to load the filter is made and if it succeeds, the loaded filter is returned.\n     * If loading fails, the method returns {@code null}.\n     *\n     * @return {@link FilterFactory#AlwaysPresent}, loaded filter or {@code null} (which means that the filter should be rebuilt)\n     */\n    public static IFilter maybeLoadBloomFilter(Descriptor descriptor, Set<Component> components, TableMetadata metadata, ValidationMetadata validationMetadata)\n    {\n        double currentFPChance = validationMetadata != null ? validationMetadata.bloomFilterFPChance : Double.NaN;\n        double desiredFPChance = metadata.params.bloomFilterFpChance;\n\n        IFilter filter = null;","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/sstable/format/FilterComponent.java#L68-L104","documentation":"FilterComponent.save() wraps any IOException encountered while persisting a SSTable's Bloom filter (the FILTER component) and rethrows it with the descriptor's base file name appended, preserving the cause. Cassandra throws this when flushing or streaming fails to write the bloom filter to disk successfully.","triggerScenarios":"Calling save() during SSTable flush/compaction/streaming when writing Components.FILTER to disk fails: disk full, I/O error, directory removed, or sync() failure. If deleteOnFailure is set, the partial filter file is deleted before rethrowing.","commonSituations":"Disk-full or disk-failure during flush; snapshot/restore operations with missing data directories; filesystem errors (EIO, ENOSPC) on the data volume; concurrent deletion of the descriptor's directory.","solutions":["Check disk space and filesystem health (df -h, dmesg for I/O errors) on the data directory and free space or fix the disk","Retry the flush/compaction after resolving the I/O condition; the failed filter file is deleted automatically when deleteOnFailure is set","Verify permissions on the SSTable directory allow the Cassandra process to create files","If it recurs on specific disks, run nodetool scrub or move the node out of rotation and rebuild it"],"exampleFix":"// before: ignoring disk pressure and retrying immediately\ntry { writeSSTable(); } catch (IOException e) { retry(); }\n// after: check disk space and handle IOException specifically\ntry { writeSSTable(); }\ncatch (IOException e) {\n    if (e.getMessage().startsWith(\"Failed to save Bloom filter\")) {\n        ensureDiskSpace(dataDir);\n        retryWithBackoff();\n    } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// before flush/save\nif (Files.getUsableSpace(dataDir.toPath()) < requiredBytes) { freeSpace(); }\ndescriptor.fileFor(Components.FILTER).getParentFile().canWrite();","typeGuard":null,"tryCatchPattern":"try { filterComponent.save(descriptor, filter, cleanup); }\ncatch (IOException e) {\n    if (e.getMessage().startsWith(\"Failed to save Bloom filter\")) {\n        logger.error(\"Bloom filter save failed for {}\", descriptor.baseFile(), e.getCause());\n        checkDiskSpaceAndFilesystem();\n    } else throw e;\n}","preventionTips":["Monitor disk usage and alert before the data volume fills","Watch OS logs for I/O errors on data disks","Keep SSTable directories writable by the Cassandra user only","Avoid external processes deleting files under the data directory"],"tags":["io","sstable","bloom-filter","disk"],"backgroundTag":"file-write-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}