All rules Rule SR010 · DW
SurrealDB · beta
warning
DW · Deploy window
free in the CLI, --engine=surrealdb

Why do updates fail after I make a SurrealDB field READONLY?

READONLY on a field of an existing table

Warning: the statement succeeds, then writes fail, access changes, or the table is held up.

What happens

Observed on SurrealDB 3.0.2: after DEFINE FIELD status ON invoice TYPE string READONLY, UPDATE invoice:1 SET status = 'paid' fails with "Found changed value for field `status`, with record `invoice:1`, but field is readonly". A READONLY field computed with VALUE left updates of the stored record working.

Why it is dangerous on a populated table

SurrealDB checks a schema change against new writes, not the records already stored, so an empty table hides it: on a populated one every old record is a write waiting to fail, and whole-table work runs for the length of the table in one transaction.

Fires on

ALTER FIELD status ON TABLE invoice READONLY;

The safe pattern

Release the code that stops updating the field first, then make it READONLY. A READONLY field that SurrealDB computes with VALUE is safe to add, and the rule stays silent on it.

DEFINE FIELD created_at ON TABLE invoice TYPE option<datetime> VALUE time::now() READONLY;

Fixtures

The rule ships with these files and the test suite runs them on every change: the first set must fire, the second must stay silent.

Fires (2)

alter readonly
ALTER FIELD status ON TABLE invoice READONLY;
overwrite readonly
DEFINE FIELD OVERWRITE status ON TABLE invoice TYPE string READONLY;

Stays silent (2)

computed readonly
DEFINE FIELD created_at ON TABLE invoice TYPE option<datetime> VALUE time::now() READONLY;
new table
DEFINE TABLE invoice SCHEMAFULL;
DEFINE FIELD number ON TABLE invoice TYPE string READONLY;

How to check locally

Catch this before it ships

SurrealDB support is in beta: this rule runs locally in the free CLI over .surql migrations, static only, and not in the hosted service yet. No install, nothing leaves your machine:

npx bolvrk check migration.surql --engine=surrealdb