{"record":{"id":"4af25500bb52043c","repo":"chenhg5/cc-connect","slug":"session-cancelled","errorCode":null,"errorMessage":"session cancelled","messagePattern":"session cancelled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"core/engine.go","lineNumber":10367,"sourceCode":"\tagentSession := state.agentSession\n\tclosePlatform := state.platform\n\tcloseReplyCtx := state.replyCtx\n\tstate.mu.Unlock()\n\n\t// If the agent session supports graceful turn cancellation (e.g. ACP),\n\t// send a cancel notification and keep the session alive for the next\n\t// user message, rather than killing the process and destroying state.\n\tif canceller, ok := agentSession.(AgentSessionCanceller); ok && agentSession != nil {\n\t\t// Keep the state in the map so the next message reuses this session.\n\t\t// Don't markStopped — the session is still usable.\n\t\t// Don't delete from interactiveStates — keep it alive.\n\t\te.interactiveMu.Unlock()\n\n\t\tif pending != nil {\n\t\t\tpending.resolve()\n\t\t}\n\t\tif notifyQueued {\n\t\t\te.notifyDroppedQueuedMessages(state, fmt.Errorf(\"session cancelled\"))\n\t\t} else {\n\t\t\tstate.mu.Lock()\n\t\t\tstate.pendingMessages = nil\n\t\t\tstate.mu.Unlock()\n\t\t}\n\n\t\t// Mark eventsNeedResync so the next turn drains stale events from\n\t\t// the cancelled turn before processing fresh input.\n\t\tstate.mu.Lock()\n\t\tstate.eventsNeedResync = true\n\t\tstate.mu.Unlock()\n\n\t\tcancelErr := canceller.CancelTurn()\n\t\tif cancelErr != nil {\n\t\t\tslog.Warn(\"agent session CancelTurn failed, falling back to Close\",\n\t\t\t\t\"session_key\", sessionKey, \"error\", cancelErr)\n\t\t\t// Fall through to normal cleanup below.\n\t\t\tgoto normalCleanup","sourceCodeStart":10349,"sourceCodeEnd":10385,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/engine.go#L10349-L10385","documentation":"Notification reason attached when a session cancellation drops pending (queued) messages: on /cancel or equivalent, any pending permission request is resolved and either the queued messages get a \"session cancelled\" notification via notifyDroppedQueuedMessages, or the queue is silently cleared. It tells the user why their queued messages never ran.","triggerScenarios":"User issues /cancel (or the cancel API) while messages sit in state.pendingMessages; notifyQueued=true routes the error string to the dropped-message notifier instead of silently discarding the queue.","commonSituations":"User cancels a long-running agent task while follow-up messages are still queued; automated scripts fire messages then cancel; user changes mind mid-task.","solutions":["Expected behavior, not a fault: re-send the messages after starting a new session","If unintentional, avoid /cancel while messages are queued; check the session has no pendingMessages first","Drain/complete the current task before issuing /cancel if the queued work is still wanted"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"This is an intentional notification, not an exception: handle the dropped-message notification by surfacing it to the user and offering to re-send queued content after a new session starts.","preventionTips":["Don't /cancel when pendingMessages may hold work you still want","Let running tasks finish or explicitly drain the queue before cancelling","Automate re-queueing: capture the dropped-message notification keys and re-send after session restart"],"tags":["go","session-lifecycle","message-queue","cancellation"],"backgroundTag":"session-cancelled","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}