HA: ClassCastException 'RaftReplicatedDatabase cannot be cast to LocalDatabase' on leader during import / read-only property write (original) (raw)
Summary
Customer (running 3-node Raft HA on Kubernetes) sees the following at runtime on the leader pod during database import:
class com.arcadedb.server.ha.raft.RaftReplicatedDatabase cannot be cast to class com.arcadedb.database.LocalDatabase
This is a real bug in engine code that performs a hard cast to LocalDatabase against the database reference exposed to documents and types. When HA is enabled, that reference is the RaftReplicatedDatabase wrapper, and the cast fails. Without HA the cast succeeds because there is no wrapper, which is why the same code path works in single-node mode.
Affected versions
- 26.5.1-SNAPSHOT (current
main) - Likely also 26.4.x (same code path, same wrapping pattern)
Confirmed call sites
These are the spots in production code that cast directly to LocalDatabase instead of going through getEmbedded() / getWrappedDatabaseInstance():
engine/src/main/java/com/arcadedb/database/DocumentValidator.java:80- read-only property validation:
final Document originalDocument = ((LocalDatabase) document.getDatabase()).getOriginalDocument(document);
Hit whenever aMutableDocument.save()runs and the type has at least onereadonlyproperty and the document is dirty + already persisted. The customer's import workload is the trigger.engine/src/main/java/com/arcadedb/schema/LocalDocumentType.java:1246- external-property bucket creation:
final String overridePath = ((LocalDatabase) schema.getDatabase()).resolveExternalBucketPath();engine/src/main/java/com/arcadedb/schema/LocalDocumentType.java:1289-reclaimEmptyExternalBuckets()precondition:
if (((LocalDatabase) schema.getDatabase()).isTransactionActive())
There may be more in modules I haven't searched (gremlin, graphql, etc.); a global review for (LocalDatabase) against any database reference that can be HA-wrapped is part of the fix.
Proposed fix
Route the cast through the wrapper:
- For
DocumentInternal.getDatabase()callers, resolve the embedded database viadatabase.getWrappedDatabaseInstance()(returns aDatabaseInternalthat, in the HA case, is the underlyingLocalDatabase). - For
Schema.getDatabase()callers, the same: castgetWrappedDatabaseInstance(). - Add a regression test that exercises read-only property validation under HA so this stays caught.
The test fixture RaftReplication3NodesIT already shows the pattern: get ServerDatabase, call .getWrappedDatabaseInstance(), then cast.
Reproduction
- Start a 3-node Raft HA cluster (any 26.x build with the Raft plugin).
- Define a type with at least one
readonlyproperty:CREATE PROPERTY MyType.id STRING (READONLY TRUE). - From the leader pod, insert a record, commit, then update any other field on the same record.
- The save fails with the ClassCastException above.
A minimal failing test would create the schema in a 3-node HA setup and update an existing record with a read-only property present.
Customer impact
- Blocks bulk imports on the leader when the imported schema has any
readonlyproperty. - Blocks any application that uses
readonlyproperties in conjunction with HA.
Related
Tracked alongside #4083 (HA leader-churn resilience and replica health visibility, fixed in commit 203acdaac). This bug is independent (it is a wrapping / casting problem in the engine, not a Raft replication problem), but customers usually trigger both at once during HA import workloads.