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

  1. Verify the sessionId came from the same user's copilot chats/sessions query and was not modified
  2. Re-fetch the user's session list and confirm the id still exists before retrying
  3. If the session was deleted, create a new session and repost the message
  4. 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

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


AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18). Data as JSON: /api/errors/12bcca37f97ed192. Report an issue: GitHub.