toeverything/AFFiNE · error · NotFoundException
Session not found
Error message
Session not found
What it means
NotFoundException('Session not found') from the copilot.session GraphQL field: after assertPermission passes, chatSession.getMetaState(sessionId) returned no state — the session id does not exist (or its projection state was never built/purged). Distinct from the ownership check in inbox.ts: here permission was already established for the workspace/doc, and the failure is purely data lookup.
Source
Thrown at packages/backend/server/src/plugins/copilot/resolver.ts:443
.allowLocal()
.assert('Workspace.Copilot');
}
return { userId: user.id, workspaceId, docId: docId || undefined };
}
@ResolveField(() => CopilotSessionType, {
description: 'Get the session by id',
complexity: 2,
})
async session(
@Parent() copilot: CopilotType,
@CurrentUser() user: CurrentUser,
@Args('sessionId') sessionId: string
): Promise<CopilotSessionType> {
await this.assertPermission(user, copilot);
const state = await this.chatSession.getMetaState(sessionId);
if (!state) {
throw new NotFoundException('Session not found');
}
const projected = this.historyProjector.projectSession(state, {
requestUserId: user.id,
skipVisibilityFilter: true,
});
if (!projected) {
throw new NotFoundException('Session not found');
}
return this.transformToSessionType(projected);
}
@ResolveField(() => [CopilotSessionType], {
description: 'Get the session list in the workspace',
deprecationReason: 'use `chats` instead',
complexity: 2,
})View on GitHub (pinned to b4c8548c09)
Solutions
- Re-query the session list and drop ids that 404, then let the user pick a live session
- For deep links, catch the NotFoundException and redirect to the session list
- Verify the sessionId string is passed unchanged (no trimming/encoding artifacts)
Example fix
# before
query { copilot { session(sessionId: $staleId) { id messages } } }
# after
# client: on SESSION_NOT_FOUND error, refetch list and navigate
try {
const s = await fetchSession(sessionId);
} catch (e) {
if (e.code === 'NOT_FOUND') router.replace('/copilot/chats');
} Defensive patterns
Strategy: try-catch
Validate before calling
const state = await chatSession.getMetaState(sessionId);
if (!state) {
await refreshSessionList();
throw new Error('Session no longer exists');
} Try / catch
try {
return await fetchCopilotSession(copilot, sessionId);
} catch (e) {
if (e instanceof NotFoundException && /Session not found/.test(e.message)) {
removeSessionFromCache(sessionId);
navigateTo('/copilot/chats');
} else throw e;
} Prevention
- Purge session ids from local cache on delete events
- Deep links should tolerate 404s by falling back to the session list
- Pass session ids through untouched — no trimming or re-encoding
When it happens
Trigger: Querying copilot session with a deleted/never-existing sessionId; session state evicted by retention/GC; id copied with extra characters; race where the session list showed an entry that was deleted before the detail query.
Common situations: Stale session list in the UI after deletion in another tab; deep link to a removed session; migration dropped old session state.
Related errors
- copilot_session_not_found
- Workspace not found
- copilot_session_not_found
- copilot_transcription_job_not_found
- user_not_found
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/133bd08e016b44e3.
Report an issue: GitHub.