toeverything/AFFiNE · error · ExpectToPublishDoc
expect_to_publish_doc
expect_to_publish_doc
Error message
Expected to publish a doc, not a Space.
What it means
Thrown by the publishPage/publishDoc mutation when workspaceId === docId. In AFFiNE the workspaceId is itself the root doc id, so publishing 'the workspace doc' is meaningless - the server rejects it up front and logs at error level. ExpectToPublishDoc is an invalid_input error.
Source
Thrown at packages/backend/server/src/core/workspaces/resolvers/doc.ts:474
@Mutation(() => DocType)
async publishDoc(
@CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string,
@Args('docId') docId: string,
@Args({
name: 'mode',
type: () => PublicDocMode,
nullable: true,
defaultValue: PublicDocMode.Page,
})
mode: PublicDocMode
) {
if (workspaceId === docId) {
this.logger.error('Expect to publish doc, but it is a workspace', {
workspaceId,
docId,
});
throw new ExpectToPublishDoc();
}
await this.ac.user(user.id).doc(workspaceId, docId).assert('Doc.Publish');
await this.assertCanShare(user.id, {
workspaceId,
docId,
action: 'publishDoc',
});
const doc = await this.models.doc.publish(workspaceId, docId, mode);
this.event.emit('doc.public_state.changed', { workspaceId, docId });
this.logger.log(
`Publish page ${docId} with mode ${mode} in workspace ${workspaceId}`
);
return doc;
}View on GitHub (pinned to 26c515e050)
Solutions
- Ensure the docId passed to publishDoc is a child page id, never the workspace root id.
- Add a client-side guard: disable the publish action when docId === workspaceId.
- Fix the upstream selection logic that surfaced the workspace root as a publishable doc.
Example fix
// before
await gql.publishDoc({ workspaceId, docId: workspaceId, mode });
// after - guard before calling
if (docId === workspaceId) {
throw new Error('Cannot publish the workspace root doc');
}
await gql.publishDoc({ workspaceId, docId, mode }); Defensive patterns
Strategy: validation
Validate before calling
// Never publish the workspace root
if (docId === workspaceId) {
throw new Error('Cannot publish the workspace root doc');
}
await gql.publishDoc({ workspaceId, docId, mode }); Type guard
function isExpectToPublishDoc(e: unknown): boolean {
return (
typeof e === 'object' &&
e !== null &&
(e as any).extensions?.code === 'expect_to_publish_doc'
);
} Try / catch
try {
await gql.publishDoc({ workspaceId, docId, mode });
} catch (e) {
if (isExpectToPublishDoc(e)) {
// bug in selection logic; do not retry, fix the docId source
reportBug('publishDoc called with workspaceId as docId');
return;
}
throw e;
} Prevention
- Disable the publish action on the workspace root in the UI.
- Keep workspaceId and docId as distinct typed primitives to avoid confusion.
- Add an assertion in the client SDK: assert(docId !== workspaceId).
When it happens
Trigger: Calling publishDoc with docId equal to workspaceId (e.g. passing the workspace root id where a child page id is expected).
Common situations: Frontend bug reusing the workspace id as the page id; user selecting the workspace root in a publish dialog; copy/paste of the workspace id into a doc publish field.
Related errors
- expect_to_revoke_public_doc
- expect_to_grant_doc_user_roles
- bad_request
- email_token_not_found
- same_email_provided
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/9f754ec2408cdc51.
Report an issue: GitHub.