{"record":{"id":"10c73c2d57742e6c","repo":"apache/cassandra","slug":"the-result-of-icompressor-serializedas-s-of-a","errorCode":null,"errorMessage":"The result of ICompressor.serializedAs(), %s, of a compressor object created by a compressor provider %s does not match the compressor class to get a compressor for. You need to override serializedAs() method of your custom compressor and return base compressor class it is the substitute for.","messagePattern":"The result of ICompressor\\.serializedAs\\(\\), (.+?), of a compressor object created by a compressor provider (.+?) does not match the compressor class to get a compressor for\\. You need to override serializedAs\\(\\) method of your custom compressor and return base compressor class it is the substitute for\\.","errorType":"validation","errorClass":"ConfigurationException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/compress/CompressorRegistry.java","lineNumber":189,"sourceCode":"\n            if (provider.isFailOnMissingProvider())\n                throw t;\n\n            compressor = DEFAULT_COMPRESSION_PROVIDER.createCompressor(compressorClass, compressionOptions);\n        }\n\n        // Validate the masquerade target for both the provider and the fallback path: whatever is\n        // returned must serialize as exactly the compressor class that was requested, otherwise the\n        // schema / on-disk format would record a name that cannot be resolved on peers and restarts.\n        Class<? extends ICompressor> serializedAs = compressor.serializedAs();\n        if (serializedAs == null || serializedAs.getSimpleName().isEmpty())\n            throw new ConfigurationException(String.format(\"ICompressor.serializedAs() of a compressor created by provider %s returned %s. \" +\n                                                           \"It must return a non-anonymous built-in compressor class in package \" +\n                                                           \"org.apache.cassandra.io.compress.\",\n                                                           provider.getClass(),\n                                                           serializedAs));\n        if (serializedAs != compressorClass)\n            throw new ConfigurationException(String.format(\"The result of ICompressor.serializedAs(), %s, of a compressor object created \" +\n                                                           \"by a compressor provider %s does not match the compressor class to get a compressor for. \" +\n                                                           \"You need to override serializedAs() method of your custom compressor and return \" +\n                                                           \"base compressor class it is the substitute for.\",\n                                                           serializedAs,\n                                                           provider.getClass()));\n        return compressor;\n    }\n\n    /**\n     * Populates the registry with compression providers specified in the configuration.\n     * Should be called once during initialization to ensure providers are registered and available\n     * for use. If a provider fails to initialize and fallback is enabled, the default provider is used.\n     * <p>\n     * Each invocation constructs fresh provider instances and re-runs {@link AbstractCompressionProvider#init}\n     * without tearing down any previously registered instance, so a custom provider that acquires\n     * resources (native memory, threads, handles) in {@code init()} must tolerate being discarded if\n     * this is called more than once (as tests do via {@link #reset()}).\n     *","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/compress/CompressorRegistry.java#L171-L207","documentation":"When getCompressor() creates a compressor through a custom compression provider, it validates that the returned ICompressor's serializedAs() result equals the compressor class that was actually requested. A mismatch means the custom compressor would be written to the schema with a name that cannot be resolved back to the class it substitutes for, corrupting the on-disk/s-schema identity. Cassandra throws ConfigurationException so the operator fixes the provider's serializedAs() override before the name ever lands in a table schema.","triggerScenarios":"Calling CompressorRegistry.getCompressor(compressorClass, options) with a registered custom provider whose returned compressor overrides serializedAs() to a Class different from the requested compressorClass (e.g. returning the provider's own subclass or a different built-in class than the one requested).","commonSituations":"Writing a custom AbstractCompressionProvider that wraps or replaces LZ4/Snappy/Deflate; the author overrides serializedAs() incorrectly (or does not override it so it returns the custom class itself), then creates a table with compression options mapping to a built-in compressor key.","solutions":["Override serializedAs() in the custom compressor class returned by your provider and return the exact built-in compressor Class it substitutes for (e.g. return LZ4Compressor.class).","Ensure the Class returned by serializedAs() is identical (same Class object) to the compressorClass passed to getCompressor() — not just an equal-named class from another classloader.","Confirm the returned class is a non-anonymous class in org.apache.cassandra.io.compress; anonymous classes fail the preceding null/empty check.","If you intended the built-in implementation, remove the custom provider registration from compressor_providers and let DefaultCompressionProvider handle the algorithm."],"exampleFix":"// before\npublic Class<? extends ICompressor> serializedAs() { return MyLz4Wrapper.class; }\n// after\n@Override\npublic Class<? extends ICompressor> serializedAs() { return LZ4Compressor.class; }","handlingStrategy":"validation","validationCode":"Class<? extends ICompressor> as = myCompressor.serializedAs();\nif (as == null || as.getSimpleName().isEmpty() || as != requestedCompressorClass)\n    throw new IllegalStateException(\"serializedAs() must return the exact requested built-in class: \" + requestedCompressorClass);","typeGuard":"boolean isValidMasquerade(ICompressor c, Class<?> requested) {\n    Class<? extends ICompressor> as = c.serializedAs();\n    return as != null && !as.getSimpleName().isEmpty() && as == requested;\n}","tryCatchPattern":"try {\n    registry.getCompressor(LZ4Compressor.class, opts);\n} catch (ConfigurationException e) {\n    if (e.getMessage().contains(\"serializedAs\")) { /* fix provider's serializedAs override */ }\n    throw e;\n}","preventionTips":["Always override serializedAs() in custom compressors to return the built-in class being substituted","Unit-test that serializedAs() returns the identical Class object (not an equal class from another classloader) as the requested class","Never return anonymous or local classes from serializedAs()","Add a startup self-check that creates each configured compressor and asserts the masquerade contract"],"tags":["configuration","compression","schema"],"backgroundTag":"invalid-config-value","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"}