{"record":{"id":"7f4ad7f202fee64a","repo":"chenhg5/cc-connect","slug":"no-active-session","errorCode":null,"errorMessage":"no active session","messagePattern":"no active session","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/copilot/session.go","lineNumber":717,"sourceCode":"\t// Handle images: save to temp dir and append file references\n\tif len(images) > 0 {\n\t\timgPaths, err := saveImagesToTempDir(cs.workDir, images)\n\t\tif err != nil {\n\t\t\tslog.Warn(\"copilotSession: failed to save images\", \"error\", err)\n\t\t} else {\n\t\t\tprompt = core.AppendFileRefs(prompt, imgPaths)\n\t\t}\n\t}\n\n\t// Handle files\n\tif len(files) > 0 {\n\t\tfilePaths := core.SaveFilesToDisk(cs.workDir, messageID, files)\n\t\tprompt = core.AppendFileRefs(prompt, filePaths)\n\t}\n\n\tsid := cs.CurrentSessionID()\n\tif sid == \"\" {\n\t\treturn fmt.Errorf(\"no active session\")\n\t}\n\n\tparams := map[string]any{\n\t\t\"sessionId\": sid,\n\t\t\"prompt\":    prompt,\n\t}\n\n\t_, sendCh := cs.rpc.call(\"session.send\", params)\n\n\t// Don't block - just validate the send was accepted\n\tgo func() {\n\t\tselect {\n\t\tcase resp := <-sendCh:\n\t\t\tif resp.Error != nil {\n\t\t\t\tslog.Error(\"copilotSession: send failed\", \"error\", resp.Error)\n\t\t\t\tif cs.alive.Load() {\n\t\t\t\t\tevt := core.Event{Type: core.EventError, Error: fmt.Errorf(\"send: %s\", resp.Error.Message)}\n\t\t\t\t\tselect {","sourceCodeStart":699,"sourceCodeEnd":735,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/copilot/session.go#L699-L735","documentation":"Before dispatching a 'session.send' RPC, Send reads the current session ID and rejects the call with 'no active session' if it is empty — meaning the JSON-RPC handshake (session.create/session.resume) never completed or the ID was reset. Without a session ID the CLI cannot attach the prompt to a conversation.","triggerScenarios":"Send is invoked while cs.CurrentSessionID() returns \"\" — handshake failed or was skipped (e.g. a prior session.resume/create timeout or error left sessionID unset), or the session was recycled without re-running handshake.","commonSituations":"Startup handshake failed earlier (see 'session.resume timeout' / 'session.create timeout') and the session object was still handed to the engine; session state cleared by /new before the new handshake finished; a race where Send arrives during session setup.","solutions":["Retry after the handshake completes — wait for the 'copilotSession: session created/resumed' log line before sending.","Fix the earlier handshake failure: check the CLI is installed, authenticated, and starts within 10s.","Run /new to force a clean session creation, then resend.","Restart cc-connect so handshake runs again from scratch.","If racing during startup, ensure the caller only sends after StartSession returns successfully."],"exampleFix":"// before: send immediately after a failed handshake\nsess, _ := agent.StartSession(ctx, opts) // handshake failed, sessionId empty\nsess.Send(\"hi\", id, nil, nil)            // \"no active session\"\n// after: check handshake error before using the session\nsess, err := agent.StartSession(ctx, opts)\nif err != nil {\n    return fmt.Errorf(\"start session: %w\", err)\n}\nsess.Send(\"hi\", id, nil, nil)","handlingStrategy":"validation","validationCode":"if session.CurrentSessionID() == \"\" {\n    return fmt.Errorf(\"session handshake not completed; cannot send\")\n}","typeGuard":"func hasActiveSession(s *copilotSession) bool { return s.CurrentSessionID() != \"\" }","tryCatchPattern":"if err := session.Send(prompt, msgID, nil, nil); err != nil && strings.Contains(err.Error(), \"no active session\") {\n    // handshake failed earlier; recreate the session then resend\n    session = agent.StartSession(ctx, opts)\n    err = session.Send(prompt, msgID, nil, nil)\n}","preventionTips":["Only send after StartSession returns nil error (handshake completed)","Watch for 'session created/resumed' log lines before first send","Fix any earlier resume/create timeout errors — they leave no session ID","Avoid sending during session setup; queue messages until ready"],"tags":["session-lifecycle","send","handshake","state-error"],"backgroundTag":"invalid-state-transition","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"}