{"record":{"id":"00a7142bbc733bfd","repo":"hibernate/hibernate-orm","slug":"can-t-update-read-only-object","errorCode":null,"errorMessage":"Can't update read-only object","messagePattern":"Can't update read-only object","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/cache/spi/support/EntityReadOnlyAccess.java","lineNumber":81,"sourceCode":"\t}\n\n\t@Override\n\tpublic void unlockItem(\n\t\t\t@Nonnull SharedSessionContractImplementor session,\n\t\t\t@Nonnull Object key,\n\t\t\t@Nullable SoftLock lock) {\n\t\tevict( key );\n\t}\n\n\t@Override\n\tpublic boolean update(\n\t\t\t@Nonnull SharedSessionContractImplementor session,\n\t\t\t@Nonnull Object key,\n\t\t\t@Nonnull Object value,\n\t\t\t@Nullable Object currentVersion,\n\t\t\t@Nullable Object previousVersion) {\n//\t\tLOG.debugf( \"Illegal attempt to update item cached as read-only [%s]\", key );\n\t\tthrow new UnsupportedOperationException( \"Can't update read-only object\" );\n\t}\n\n\t@Override\n\tpublic boolean afterUpdate(\n\t\t\t@Nonnull SharedSessionContractImplementor session,\n\t\t\t@Nonnull Object key,\n\t\t\t@Nonnull Object value,\n\t\t\t@Nullable Object currentVersion,\n\t\t\t@Nullable Object previousVersion,\n\t\t\t@Nullable SoftLock lock) {\n//\t\tLOG.debugf( \"Illegal attempt to update item cached as read-only [%s]\", key );\n\t\tthrow new UnsupportedOperationException( \"Can't write to a read-only object\" );\n\t}\n}\n","sourceCodeStart":63,"sourceCodeEnd":96,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/cache/spi/support/EntityReadOnlyAccess.java#L63-L96","documentation":"The read-only cache concurrency strategy assumes cached entities never change, so EntityReadOnlyAccess implements update() by throwing UnsupportedOperationException. When a session flushes modifications to an entity whose region uses the read-only strategy, the second-level cache callback reaches this method and the flush fails. It is the strategy telling you the mapping contract (immutable data) was violated.","triggerScenarios":"Mapping an entity with @Cache(usage = READ_ONLY) and then modifying instances and flushing; setting hibernate.cache.default_cache_concurrency_strategy=read-only globally while some entities are mutable; import or admin jobs updating reference data that is cached read-only.","commonSituations":"'Reference data' cached READ_ONLY that later becomes editable through new features; a global read-only default chosen for performance; copying the cache annotation from an immutable entity onto a mutable one.","solutions":["Switch the entity to CacheConcurrencyStrategy.READ_WRITE or NONSTRICT_READ_WRITE if it is mutable","Keep the entity immutable and remove the update path instead of fighting the strategy","For bulk-replaced data, evict the region after loading the new dataset rather than per-row updates","Fix a bad global default: hibernate.cache.default_cache_concurrency_strategy must not be read-only for mutable entities"],"exampleFix":"// before\n@Entity\n@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)\npublic class Product { ... } // product.setPrice(p); em.flush(); -> throws\n\n// after\n@Entity\n@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)\npublic class Product { ... }","handlingStrategy":"validation","validationCode":"org.hibernate.annotations.Cache cache =\n        Product.class.getAnnotation(org.hibernate.annotations.Cache.class);\nif (cache != null && cache.usage() == CacheConcurrencyStrategy.READ_ONLY) {\n    throw new IllegalStateException(\n            \"Refusing to update entity cached with read-only strategy: Product\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.flush();\n} catch (UnsupportedOperationException e) {\n    if (\"Can't update read-only object\".equals(e.getMessage())) {\n        throw new IllegalStateException(\n                \"Entity is cached READ_ONLY but was modified - fix the @Cache usage\", e);\n    }\n    throw e;\n}","preventionTips":["Reserve READ_ONLY strategy for truly immutable entities","Run a startup audit flagging mutable entities mapped with READ_ONLY","Review the global default cache strategy whenever write paths are added"],"tags":["hibernate","second-level-cache","read-only","concurrency-strategy","flush"],"backgroundTag":"write-to-read-only-cache","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}