Summary
CacheHandler rejects any non-cross-SDK serializer (notably auto) whenever encryption=True, gated purely on the encryption flag with no consideration of the backend. For a local, single-language FileBackend — read only by the Python SDK — the cross-SDK-interop rationale does not apply, yet auto + encryption is still a hard ConfigurationError. This conflates encrypted with cross-SDK-shared.
Where (source v0.9.0, installed 0.9.1)
src/cachekit/cache_handler.py:
# line 33
CROSS_SDK_SERIALIZER_NAMES = ("default", "std", "standard", "orjson", "arrow")
# line 348 — the guard's only enclosing condition is the encryption flag; no backend check
if self.encryption:
...
if isinstance(serializer_name, str):
if serializer_name not in CROSS_SDK_SERIALIZER_NAMES:
raise ConfigurationError(
"Encryption requires a cross-SDK-compatible serializer for cross-language "
"interop, got serializer='...'. ... The 'auto' serializer emits "
"Python-specific types that other SDKs cannot decode, so it cannot be used with encryption."
)
elif not getattr(type(serializer_name), "cross_sdk_compatible", False):
raise ConfigurationError(...)
Why this is over-coupled
Serialization and encryption are already orthogonal in the implementation: EncryptionWrapper is a Decorator that composes any SerializerProtocol with the AES-256-GCM layer and threads the user's serializer through (it is not silently replaced, post-#134). So nothing technical forces encryption to constrain the serializer — the only coupling is this policy guard.
The guard's justification — "so the encrypted bytes remain decodable by other-language SDKs" — holds only when another-language SDK actually reads the cache. That is a property of the backend (SaaS CachekitIO / any shared store), not of encryption. A local FileBackend encrypted at rest and read solely by the Python process has no other-SDK reader, so requiring a cross-SDK wire format there buys nothing and costs auto's Python-type fidelity (sets, frozensets, datetime, UUID, Decimal, NumPy, pandas).
Impact
Anyone wanting an encrypted local cache that preserves rich Python types is forced onto std/orjson (JSON-ish types only), or must normalize/model_dump() every payload before the cache boundary. The only current escape is a custom serializer declaring cross_sdk_compatible=True — i.e. asserting a cross-SDK guarantee the cache does not actually need.
Proposed fix
Gate the cross-SDK serializer requirement on the backend's cross-SDK exposure, not on self.encryption:
- SaaS /
CachekitIO / any shared or cross-SDK backend → require a CROSS_SDK_SERIALIZER_NAMES serializer (current behavior).
- Local single-SDK backend (
FileBackend, in-process) → allow auto and other non-cross-SDK serializers with encryption; EncryptionWrapper still wraps the emitted bytes regardless.
Alternatively, an explicit opt-out (e.g. a backend capability flag / allow_local_serializer=True) for callers who know their encrypted cache is single-SDK.
Refs #134, which added this validation while wiring the user serializer through EncryptionWrapper.
Summary
CacheHandlerrejects any non-cross-SDK serializer (notablyauto) wheneverencryption=True, gated purely on the encryption flag with no consideration of the backend. For a local, single-languageFileBackend— read only by the Python SDK — the cross-SDK-interop rationale does not apply, yetauto+ encryption is still a hardConfigurationError. This conflates encrypted with cross-SDK-shared.Where (source v0.9.0, installed 0.9.1)
src/cachekit/cache_handler.py:Why this is over-coupled
Serialization and encryption are already orthogonal in the implementation:
EncryptionWrapperis a Decorator that composes anySerializerProtocolwith the AES-256-GCM layer and threads the user's serializer through (it is not silently replaced, post-#134). So nothing technical forces encryption to constrain the serializer — the only coupling is this policy guard.The guard's justification — "so the encrypted bytes remain decodable by other-language SDKs" — holds only when another-language SDK actually reads the cache. That is a property of the backend (SaaS
CachekitIO/ any shared store), not of encryption. A localFileBackendencrypted at rest and read solely by the Python process has no other-SDK reader, so requiring a cross-SDK wire format there buys nothing and costsauto's Python-type fidelity (sets, frozensets, datetime, UUID, Decimal, NumPy, pandas).Impact
Anyone wanting an encrypted local cache that preserves rich Python types is forced onto
std/orjson(JSON-ish types only), or must normalize/model_dump()every payload before the cache boundary. The only current escape is a custom serializer declaringcross_sdk_compatible=True— i.e. asserting a cross-SDK guarantee the cache does not actually need.Proposed fix
Gate the cross-SDK serializer requirement on the backend's cross-SDK exposure, not on
self.encryption:CachekitIO/ any shared or cross-SDK backend → require aCROSS_SDK_SERIALIZER_NAMESserializer (current behavior).FileBackend, in-process) → allowautoand other non-cross-SDK serializers with encryption;EncryptionWrapperstill wraps the emitted bytes regardless.Alternatively, an explicit opt-out (e.g. a backend capability flag /
allow_local_serializer=True) for callers who know their encrypted cache is single-SDK.Refs #134, which added this validation while wiring the user serializer through
EncryptionWrapper.