toeverything/AFFiNE · warning · DocUpdateBlocked
doc_update_blocked
doc_update_blocked
Error message
Doc ${docId} under Space ${spaceId} is blocked from updating. What it means
Thrown by WorkspaceSyncAdapter.push() when the doc's metadata row has blocked === true. The block flag is read from the doc meta model before any update is written, so a blocked doc rejects all incoming Yjs updates for that (spaceId, docId). The check is specific to the Workspace space type; Userspace pushes bypass it.
Source
Thrown at packages/backend/server/src/core/sync/gateway.ts:966
private readonly docReader: DocReader,
private readonly models: Models
) {
super(SpaceType.Workspace, client, storage);
}
override async push(
spaceId: string,
docId: string,
updates: Buffer[],
editorId: string
) {
const docMeta = await this.models.doc.getMeta(spaceId, docId, {
select: {
blocked: true,
},
});
if (docMeta?.blocked) {
throw new DocUpdateBlocked({ spaceId, docId });
}
return await super.push(spaceId, docId, updates, editorId);
}
override async diff(
spaceId: string,
docId: string,
stateVector?: Uint8Array
) {
return await this.docReader.getDocDiff(spaceId, docId, stateVector);
}
async assertAccessible(
spaceId: string,
userId: string,
action: WorkspaceAction
) {
await this.ac.user(userId).workspace(spaceId).assert(action);View on GitHub (pinned to 26c515e050)
Solutions
- Check whether the doc is intentionally blocked via admin tooling before escalating.
- On the client, surface a read-only / locked indicator and stop pushing updates for that docId when this error is received.
- If the block is stale, clear doc_meta.blocked for the (spaceId, docId) in the database.
- Have the client re-fetch doc metadata on reconnect to learn the blocked state proactively.
Example fix
// before — keep retrying pushes on failure
socket.emit('space:push-doc-update', payload);
// after — honor the blocked state
try {
await socket.emitWithAck('space:push-doc-update', payload);
} catch (e) {
if (e.code === 'doc_update_blocked') {
setDocReadOnly(spaceId, docId, true);
return;
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Optionally pre-fetch doc meta to learn blocked state
const meta = await fetchDocMeta(spaceId, docId);
if (meta?.blocked) { setReadOnly(docId); } Type guard
function isDocBlocked(meta?: { blocked?: boolean }): boolean {
return Boolean(meta?.blocked);
} Try / catch
try {
await socket.emitWithAck('space:push-doc-update', payload);
} catch (e) {
if (e?.code === 'doc_update_blocked') { setDocReadOnly(spaceId, docId, true); return; }
throw e;
} Prevention
- Surface a read-only UI state when the doc is blocked instead of retrying pushes.
- Re-fetch doc meta on reconnect to detect newly-blocked docs.
- Stop queuing updates for blocked docs to avoid backpressure.
When it happens
Trigger: Client emits 'space:push-doc-update' against a workspace doc whose doc_meta.blocked column is true, while still being joined and permissioned. Triggered when an admin/migration has flagged the doc read-only.
Common situations: Doc was blocked during a migration, a quota enforcement action, a legal/admin hold, or because it was merged into another doc; client still has the doc open and keeps sending edits.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/b69a5fa96cafa933.
Report an issue: GitHub.