toeverything/AFFiNE · error · DocUpdateBlocked
doc_update_blocked
doc_update_blocked
Error message
Doc ${docId} under Space ${spaceId} is blocked from updating. What it means
WorkspaceSyncAdapter.push loads the doc's metadata before persisting updates and throws doc_update_blocked when the blocked flag is true. A blocked doc is server-side write-locked (for example by moderation or a restore/maintenance flow): reads such as diff keep working, but new update pushes are rejected.
Solutions
- Stop retrying pushes for that doc immediately - the block is an intentional server state, not a transient fault
- Buffer the rejected updates locally (Yjs updates merge safely) and flush them once the doc is unblocked
- Check the doc's blocked state through the doc metadata/API to detect when writes are allowed again
- If you operate the server, finish or cancel the maintenance operation that set the flag
Example fix
// before
await adapter.push(spaceId, docId, updates, editorId);
// after
try {
await adapter.push(spaceId, docId, updates, editorId);
} catch (e) {
if (e.code === 'doc_update_blocked') {
pendingUpdates.push(...updates); // buffer, retry when unblocked
} else {
throw e;
}
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await push(spaceId, docId, updates, editorId);
} catch (e) {
if (e?.code === 'doc_update_blocked') {
pendingUpdates.push(...updates); // buffer Yjs updates locally
scheduleRetryWhenUnblocked(spaceId, docId); // e.g. poll doc metadata
} else {
throw e;
}
} Prevention
- Never retry doc_update_blocked on a timer - it is a deliberate server state, not a transient error
- Keep local update buffers durable so blocked-period updates are not lost on refresh
- Surface a 'doc is locked' state in the UI instead of silently dropping edits
- For servers you operate, announce maintenance windows that block docs
When it happens
Trigger: Pushing doc updates via the sync gateway while models.doc.getMeta(spaceId, docId) has blocked=true; a maintenance/restore job flipping the flag while clients sync; admin tooling that blocks a doc.
Common situations: Self-hosted instance in the middle of a doc migration or backup restore; a doc flagged for review; clients misreading the rejection as a network error and retry-storming.
Related errors
AI-assisted analysis of toeverything/AFFiNE@b6de0ad51b (2026-08-18).
Data as JSON: /api/errors/b69a5fa96cafa933.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/sync/gateway.ts:1532
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 b6de0ad51b)