{"record":{"id":"b718a843bce3aa7d","repo":"chenhg5/cc-connect","slug":"session-q-is-busy","errorCode":null,"errorMessage":"session %q is busy","messagePattern":"session %q is busy","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/engine.go","lineNumber":1629,"sourceCode":"\t\t\tworkspaceDir = job.WorkDir\n\t\t} else {\n\t\t\tslog.Warn(\"cron: workspace agent creation failed, using global\",\n\t\t\t\t\"work_dir\", job.WorkDir, \"session_key\", sessionKey, \"error\", err)\n\t\t}\n\t}\n\n\tuseNewSession := false\n\tif e.cronScheduler != nil {\n\t\tuseNewSession = e.cronScheduler.UsesNewSession(job)\n\t} else {\n\t\tuseNewSession = job.UsesNewSessionPerRun()\n\t}\n\n\tif useNewSession {\n\t\tmsg.SessionKey = runSessionKey\n\t\tsession := sessions.NewSideSession(runSessionKey, \"cron-\"+job.ID)\n\t\tif !session.TryLock() {\n\t\t\treturn fmt.Errorf(\"session %q is busy\", runSessionKey)\n\t\t}\n\t\tiKey := fmt.Sprintf(\"%s#cron:%s\", runSessionKey, session.ID)\n\t\tif workspaceDir != \"\" {\n\t\t\tiKey = workspaceDir + \":\" + iKey\n\t\t}\n\t\tprevHistLen := session.HistoryLen()\n\t\te.processInteractiveMessageWith(effectivePlatform, msg, session, agent, sessions, iKey, workspaceDir, runSessionKey)\n\t\te.cleanupInteractiveState(iKey)\n\t\t// Empty-response detection via session history delta: processInteractiveMessageWith\n\t\t// always adds a \"user\" entry (prevHistLen+1), then an \"assistant\" entry on success\n\t\t// (prevHistLen+2). This approach correctly detects empty responses across all\n\t\t// delivery modes (plain text, cards, rich cards, DingTalk AI streaming) because\n\t\t// AddHistory(\"assistant\",...) is called before any platform-specific rendering path.\n\t\tif !job.Mute && session.HistoryLen() < prevHistLen+2 {\n\t\t\treturn fmt.Errorf(\"cron job %q produced an empty response\", job.ID)\n\t\t}\n\t\treturn nil\n\t}","sourceCodeStart":1611,"sourceCodeEnd":1647,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/engine.go#L1611-L1647","documentation":"Cron run with new-session-per-run: the freshly created side session's TryLock failed, meaning that cron session is still processing a previous run. The current run is skipped rather than queued or double-executed.","triggerScenarios":"Thrown at core/engine.go:1629 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Wait for the overlapping run to finish or lengthen the cron schedule","Disable use_new_session_per_run so runs share the serialized main session"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}