toeverything/AFFiNE · error · BadRequestException
Session not found
Error message
Session not found
What it means
Thrown by CopilotInbox.createMessage when the referenced chat session does not exist, or exists but belongs to a different user (session.config.userId !== userId). It is a BadRequestException (HTTP 400) rather than 404, so the client sees 'Session not found' on a malformed or cross-user request. The userId check doubles as an authorization guard: you can never post into someone else's session even with a valid sessionId.
Source
Thrown at packages/backend/server/src/plugins/copilot/conversation/inbox.ts:45
};
@Injectable()
export class ConversationInboxService {
constructor(
private readonly chatSession: ChatSessionService,
private readonly ac: PermissionAccess,
private readonly models: Models,
private readonly storage: CopilotStorage,
private readonly submissions: CompatSubmissionStore
) {}
async createMessage(
userId: string,
options: CreateInboxMessage
): Promise<string> {
const session = await this.chatSession.get(options.sessionId);
if (!session || session.config.userId !== userId) {
throw new BadRequestException('Session not found');
}
const attachments: PromptMessage['attachments'] = options.attachments || [];
const blobs = await Promise.all(
options.blob ? [options.blob] : options.blobs || []
);
const focusSelectors = options.params?.focusSelectors;
const hasWorkspaceContext =
attachments.length > 0 ||
blobs.length > 0 ||
(Array.isArray(options.params?.scopeSelectors) &&
options.params.scopeSelectors.length > 0) ||
(Array.isArray(options.params?.preferredSourceIds) &&
options.params.preferredSourceIds.length > 0) ||
(focusSelectors === undefined
? session.config.focus.selectors.length > 0
: Array.isArray(focusSelectors) && focusSelectors.length > 0);View on GitHub (pinned to b4c8548c09)
Solutions
- Verify the sessionId came from the same user's copilot chats/sessions query and was not modified
- Re-fetch the user's session list and confirm the id still exists before retrying
- If the session was deleted, create a new session and repost the message
- As a maintainer: catch BadRequestException with message 'Session not found' and surface a 'start a new chat' action in the UI instead of a raw error
Example fix
// before
await inbox.createMessage(userId, { sessionId: staleId, content });
// after
const session = await chatSession.get(staleId);
if (!session || session.config.userId !== userId) {
// re-create or pick a fresh session instead of posting
throw new Error('Session is gone, start a new chat');
}
await inbox.createMessage(userId, { sessionId: staleId, content }); Defensive patterns
Strategy: validation
Validate before calling
const session = await chatSession.get(sessionId);
if (!session || session.config.userId !== currentUserId) {
throw new Error('Session unavailable — refetch session list');
} Type guard
const isOwnSession = (
s: { config: { userId: string } } | null | undefined,
userId: string
): s is { config: { userId: string } } => !!s && s.config.userId === userId; Try / catch
try {
await inbox.createMessage(userId, options);
} catch (e) {
if (e instanceof BadRequestException && e.message === 'Session not found') {
await refreshSessions(); // drop stale id, pick or create a new session
} else throw e;
} Prevention
- Always source sessionIds from a fresh session-list query for the current user
- Invalidate cached session ids on account switch or session deletion events
- Treat 'Session not found' as a signal to resync, not to blind-retry
When it happens
Trigger: Calling the copilot inbox/createMessage API with a sessionId that was deleted, never existed, or was truncated/typo'd; calling with a sessionId owned by another user account; using a stale sessionId after the user switched accounts or the session was garbage-collected.
Common situations: Frontend keeps a cached sessionId after the session list refreshed; test harness copies a sessionId from a different seeded user; session expired and was purged while the composer stayed open.
Related errors
- copilot_prompt_invalid
- copilot_session_deleted
- copilot_session_not_found
- copilot_session_invalid_input
- action_forbidden
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/12bcca37f97ed192.
Report an issue: GitHub.