toeverything/AFFiNE · error · CopilotSessionInvalidInput

copilot_session_invalid_input

copilot_session_invalid_input

Error message

Cannot update action: ${session.id}

What it means

CopilotSessionInvalidInput (invalid_input / copilot_session_invalid_input) thrown by CopilotSessionModel.update (packages/backend/server/src/models/copilot-session.ts:664). Once the session is found, update() refuses to mutate 'action' sessions from a non-internal call path. If session.promptAction is set and internalCall is false, changing the session's identity is forbidden and the guard throws with the session id.

Source

Thrown at packages/backend/server/src/models/copilot-session.ts:664

      sessionId,
      {
        id: true,
        workspaceId: true,
        docId: true,
        parentSessionId: true,
        pinned: true,
        promptAction: true,
      },
      { userId }
    );
    if (!session) {
      throw new CopilotSessionNotFound();
    }

    // not allow to update action session
    if (!internalCall) {
      if (session.promptAction) {
        throw new CopilotSessionInvalidInput(
          `Cannot update action: ${session.id}`
        );
      } else if (docId && session.parentSessionId) {
        throw new CopilotSessionInvalidInput(
          `Cannot update docId for forked session: ${session.id}`
        );
      }
    }

    let nextPromptAction: string | null | undefined;
    if (promptName) {
      nextPromptAction = options.promptAction;
      if (nextPromptAction === undefined) {
        throw new CopilotSessionInvalidInput(
          `Prompt action is required when changing prompt ${promptName}`
        );
      }
      if (nextPromptAction) {

View on GitHub (pinned to 26c515e050)

Solutions

  1. Do not call update on action sessions from user flows; create a new Doc chat session instead.
  2. If you genuinely must update, route through the internal call path that sets internalCall=true.
  3. Filter action sessions out of the editable session list in the UI (hide rows where promptAction is set).
  4. Catch copilot_session_invalid_input and tell the user this session type is not editable.

Example fix

// before
await sessionModel.update({ sessionId, userId, pinned: true });
// after
const s = await sessionModel.getExists(sessionId, { promptAction: true }, { userId });
if (s?.promptAction) throw new Error('Action sessions are not editable.');
await sessionModel.update({ sessionId, userId, pinned: true });
Defensive patterns

Strategy: validation

Validate before calling

const s = await sessionModel.getExists(sessionId, { promptAction: true }, { userId });
if (s?.promptAction) {
  throw new Error('Action sessions cannot be updated via the public path');
}
await sessionModel.update({ sessionId, userId, /* ... */ });

Type guard

const isEditableSession = (s: { promptAction: string | null }): boolean =>
  !s.promptAction;

Try / catch

try {
  await sessionModel.update(payload);
} catch (e) {
  if (e instanceof UserFriendlyError && e.code === 'copilot_session_invalid_input') {
    ui.warn('This session type is not editable.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: A user-facing (internalCall=false) update call targeting an action session — a session created with promptAction set. Such sessions are scoped to a specific action workflow and cannot be repurposed via the public update API.

Common situations: Trying to rename/move/re-pin a session that was auto-created for an action (e.g. 'Explain this doc'); frontend reusing an action session's id for a generic edit form; calling update without the internalCall flag on a session type that requires it.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/1d5813ccbc254d69. Report an issue: GitHub.