pubkey/rxdb · error · RxError
DOC9
DOC9
Error message
RxDB Error-Code: ${message}.
Hint: Error messages are not included in RxDB core to reduce build size.
To show the full error messages and to ensure that you do not make any mistakes when using RxDB,
use the dev-mode plugin when you are in development mode: https://rxdb.info/dev-mode.html?console=error
Find out more about this error here: https://rxdb.info/errors.html?console=errors#DOC9
Still stuck? Ask in the RxDB Discord: https://rxdb.info/chat
What it means
DOC9 is thrown by RxSchema.validateChange() when a document update modifies a field marked as final in the schema. Final fields are immutable after the document is created; this protects primary keys and other frozen values from diverging between replicas. The error carries dataBefore, dataAfter and the offending fieldName.
Source
Thrown at src/rx-schema.ts:122
*/
public get hash(): Promise<string> {
return overwriteGetterForCaching(
this,
'hash',
this.hashFunction(JSON.stringify(this.jsonSchema))
);
}
/**
* checks if a given change on a document is allowed
* Ensures that:
* - final fields are not modified
* @throws {Error} if not valid
*/
validateChange(dataBefore: any, dataAfter: any): void {
this.finalFields.forEach(fieldName => {
if (!deepEqual(dataBefore[fieldName], dataAfter[fieldName])) {
throw newRxError('DOC9', {
dataBefore,
dataAfter,
fieldName,
schema: this.jsonSchema
});
}
});
}
/**
* creates the schema-based document-prototype,
* see RxCollection.getDocumentPrototype()
*/
public getDocumentPrototype(): any {
const proto: any = {};
/**
* On the top level, we know all keysView on GitHub (pinned to af6fb65f94)
Solutions
- Remove the final field from your update data; only patch mutable fields.
- Use incrementalModify()/incrementalPatch with a modifier that leaves final fields untouched.
- If the field genuinely must change, remove 'final' from the schema (requires schema version bump and a migration strategy).
- To 'change' an immutable document, remove it and re-insert a new document with a new primary key.
Example fix
// before
await doc.incrementalPatch({ id: 'new-id', counter: 5 }); // id is final
// after
await doc.incrementalPatch({ counter: 5 }); // only mutable fields Defensive patterns
Strategy: try-catch
Validate before calling
function patchIsSafe(doc: RxDocument, patch: Record<string, any>): boolean {
const finalFields: string[] = (doc.collection.schema as any).finalFields;
return !finalFields.some(f =>
f in patch && !deepEqual((doc.toJSON() as any)[f], patch[f]));
} Try / catch
try {
await doc.incrementalPatch(patch);
} catch (err: any) {
if (err.code === 'DOC9') {
const field = err.parameters?.fieldName;
// strip the immutable field and retry
const { [field]: _omit, ...rest } = patch;
await doc.incrementalPatch(rest);
} else throw err;
} Prevention
- Never include the primary key in patch/update payloads.
- Strip finalFields from user-supplied update objects before applying them.
- Only mark fields final when they truly must never change; changing them later requires a schema migration.
- Build patches from explicit field lists, not from spreading whole state objects.
When it happens
Trigger: Calling doc.incrementalPatch()/incrementalModify()/update() or collection.upsert() with new data in which a final field (including the primary key and fields listed in schema.finalFields) has a value different from the stored document. deepEqual comparison fails, so even changed nested objects in a final field trigger it.
Common situations: Trying to change the primary key of an existing document; accidentally including final fields in a patch object built from spread state; upserting a full document where an immutable field was recalculated (e.g. timestamps or counters marked final); migrated code from databases without immutability rules.
Related errors
AI-assisted analysis of pubkey/rxdb@af6fb65f94 (2026-08-31).
Data as JSON: /api/errors/b10820aa771e902d.
Report an issue: GitHub.