toeverything/AFFiNE · critical
AUTHENTICATION_REQUIRED
Error message
AUTHENTICATION_REQUIRED
What it means
Error('AUTHENTICATION_REQUIRED') thrown from the authorize callback of the copilot.delegated.tool.requested realtime topic when there is no authenticated user on the socket. Subscribing to this topic (which streams tool-call requests to a delegating client) is only valid for authenticated connections; the guard runs before the room is computed.
Source
Thrown at packages/backend/server/src/plugins/copilot/delegated/realtime.ts:136
});
this.registry.registerRequest({
name: 'copilot.delegated.tool.respond',
input: responseSchema,
handle: async (user, response) => {
if (!user) return { accepted: false };
const accepted = this.delegated.receive(user.id, response);
this.event.broadcast('copilot.delegated.tool.responded', {
userId: user.id,
response,
});
return { accepted };
},
});
this.registry.registerTopic({
name: 'copilot.delegated.tool.requested',
input: z.object({ clientId: z.string().min(1).max(128) }).strict(),
authorize: async user => {
if (!user) throw new Error('AUTHENTICATION_REQUIRED');
},
room: (user, input) => {
if (!user) throw new Error('AUTHENTICATION_REQUIRED');
return realtimeUserRoom(user.id, `copilot:${input.clientId}`);
},
});
}
}
View on GitHub (pinned to b4c8548c09)
Solutions
- Authenticate the realtime connection (valid token/cookie) before subscribing to the topic
- Re-authenticate and resubscribe when the token expires mid-session
- In client code, gate topic subscription on the connection's authenticated state
Example fix
// before
socket.subscribe('copilot.delegated.tool.requested', { clientId }); // anonymous socket
// after
await socket.authenticate(token);
socket.subscribe('copilot.delegated.tool.requested', { clientId }); Defensive patterns
Strategy: validation
Validate before calling
if (!socket.isAuthenticated) {
await socket.authenticate(getToken());
}
await socket.subscribe('copilot.delegated.tool.requested', { clientId }); Try / catch
try {
await socket.subscribe('copilot.delegated.tool.requested', { clientId });
} catch (e) {
if (e.message === 'AUTHENTICATION_REQUIRED') {
await reauthenticate();
await socket.subscribe('copilot.delegated.tool.requested', { clientId });
} else throw e;
} Prevention
- Complete the auth handshake before any topic subscription
- Refresh tokens proactively before expiry so the socket never downgrades to anonymous
- Gate delegated-tool subscriptions behind the app's authenticated state
When it happens
Trigger: Subscribing to topic copilot.delegated.tool.requested over an anonymous/unauthenticated websocket; token expired before subscribe; auth handshake skipped by a custom client.
Common situations: Client subscribes before completing the auth flow; session cookie/JWT expired and the socket silently downgraded to anonymous; load-test client forgot credentials.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- authentication_required
- action_forbidden
- action_forbidden
- Session not found
- INVALID_DELEGATED_EDITOR_SESSION
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/b218e7b89351eda3.
Report an issue: GitHub.