{"record":{"id":"1d5813ccbc254d69","repo":"toeverything/AFFiNE","slug":"copilot-session-invalid-input","errorCode":"copilot_session_invalid_input","errorMessage":"Cannot update action: ${session.id}","messagePattern":"Cannot update action: (.+?)","errorType":"error_code","errorClass":"CopilotSessionInvalidInput","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/models/copilot-session.ts","lineNumber":664,"sourceCode":"      sessionId,\n      {\n        id: true,\n        workspaceId: true,\n        docId: true,\n        parentSessionId: true,\n        pinned: true,\n        promptAction: true,\n      },\n      { userId }\n    );\n    if (!session) {\n      throw new CopilotSessionNotFound();\n    }\n\n    // not allow to update action session\n    if (!internalCall) {\n      if (session.promptAction) {\n        throw new CopilotSessionInvalidInput(\n          `Cannot update action: ${session.id}`\n        );\n      } else if (docId && session.parentSessionId) {\n        throw new CopilotSessionInvalidInput(\n          `Cannot update docId for forked session: ${session.id}`\n        );\n      }\n    }\n\n    let nextPromptAction: string | null | undefined;\n    if (promptName) {\n      nextPromptAction = options.promptAction;\n      if (nextPromptAction === undefined) {\n        throw new CopilotSessionInvalidInput(\n          `Prompt action is required when changing prompt ${promptName}`\n        );\n      }\n      if (nextPromptAction) {","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/models/copilot-session.ts#L646-L682","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Do not call update on action sessions from user flows; create a new Doc chat session instead.","If you genuinely must update, route through the internal call path that sets internalCall=true.","Filter action sessions out of the editable session list in the UI (hide rows where promptAction is set).","Catch copilot_session_invalid_input and tell the user this session type is not editable."],"exampleFix":"// before\nawait sessionModel.update({ sessionId, userId, pinned: true });\n// after\nconst s = await sessionModel.getExists(sessionId, { promptAction: true }, { userId });\nif (s?.promptAction) throw new Error('Action sessions are not editable.');\nawait sessionModel.update({ sessionId, userId, pinned: true });","handlingStrategy":"validation","validationCode":"const s = await sessionModel.getExists(sessionId, { promptAction: true }, { userId });\nif (s?.promptAction) {\n  throw new Error('Action sessions cannot be updated via the public path');\n}\nawait sessionModel.update({ sessionId, userId, /* ... */ });","typeGuard":"const isEditableSession = (s: { promptAction: string | null }): boolean =>\n  !s.promptAction;","tryCatchPattern":"try {\n  await sessionModel.update(payload);\n} catch (e) {\n  if (e instanceof UserFriendlyError && e.code === 'copilot_session_invalid_input') {\n    ui.warn('This session type is not editable.');\n    return;\n  }\n  throw e;\n}","preventionTips":["Hide action sessions from the editable session list.","Reserve update() for non-action sessions unless routing through the internal path.","Document that promptAction-bearing sessions are read-only to users."],"tags":["copilot","session","action","immutable"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}