{"record":{"id":"2240bd541dea008b","repo":"chenhg5/cc-connect","slug":"acp-no-agent-session-id","errorCode":null,"errorMessage":"acp: no agent session id","messagePattern":"acp: no agent session id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/acp/session.go","lineNumber":606,"sourceCode":"}\n\nfunc (s *acpSession) Send(prompt string, messageID string, images []core.ImageAttachment, files []core.FileAttachment) error {\n\tif !s.alive.Load() {\n\t\treturn fmt.Errorf(\"acp: session closed\")\n\t}\n\n\ts.sendMu.Lock()\n\tdefer s.sendMu.Unlock()\n\n\tfilePaths := core.SaveFilesToDisk(s.workDir, messageID, files)\n\tprompt = core.AppendFileRefs(prompt, filePaths)\n\tif len(images) > 0 {\n\t\tprompt = s.appendImageRefs(prompt, images)\n\t}\n\n\tsid := s.currentACPSessionID()\n\tif sid == \"\" {\n\t\treturn fmt.Errorf(\"acp: no agent session id\")\n\t}\n\n\tpromptBlocks := []any{\n\t\tmap[string]any{\"type\": \"text\", \"text\": prompt},\n\t}\n\tparams := map[string]any{\n\t\t\"sessionId\": sid,\n\t\t\"prompt\":    promptBlocks,\n\t}\n\n\tslog.Debug(\"acp: sending session/prompt\", \"session_id\", sid, \"prompt_len\", len(prompt))\n\tres, err := s.tr.call(s.ctx, \"session/prompt\", params)\n\tif err != nil {\n\t\ts.emit(core.Event{Type: core.EventError, Error: err})\n\t\treturn fmt.Errorf(\"acp: session/prompt: %w\", err)\n\t}\n\tslog.Debug(\"acp: session/prompt response\", \"session_id\", sid, \"response_len\", len(res), \"response\", string(res))\n","sourceCodeStart":588,"sourceCodeEnd":624,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/acp/session.go#L588-L624","documentation":"A sentinel guard in acpSession.Send: before shipping the prompt over the ACP session/new or session/prompt path, the session checks its stored agent-side session ID and finds it empty. It fires when Send is called before the initialize/session/new handshake completed (or the ID was never captured), so there is no ACP session to address.","triggerScenarios":"currentACPSessionID() returns \"\" at Send time — e.g. a session object created without a completed handshake, a session/new response with empty sessionId that was somehow tolerated, or internal state corruption after close/restart.","commonSituations":"Custom embedding that constructs acpSession without running handshake; an agent that never returned a valid session id but the session was kept alive; concurrency bug clearing acpSessID.","solutions":["Ensure the session went through the full handshake (initialize → session/new or session/load) before calling Send.","Recreate the session via StartSession/newACPSession so session/new runs and caches an id.","If using a custom transport/embedding, verify setACPSessionID is called with the id from session/new.","Check agent output: an empty sessionId from session/new points back to error [45]; fix the agent first."],"exampleFix":"// before: sending right after a failed handshake\nsess, _ := agent.StartSession(ctx, id, nil) // handshake failed\nsess.Send(prompt, mid, nil, nil)            // \"acp: no agent session id\"\n// after: check the error before sending\nsess, err := agent.StartSession(ctx, id, nil)\nif err != nil {\n    return err\n}\nsess.Send(prompt, mid, nil, nil)","handlingStrategy":"validation","validationCode":"// before Send: ensure a session id exists\nif err := sess.Send(\"ping\", probeMsgID, nil, nil); err != nil && strings.Contains(err.Error(), \"no agent session id\") {\n    return fmt.Errorf(\"session not initialized; rerun StartSession\")\n}","typeGuard":null,"tryCatchPattern":"if err := sess.Send(prompt, mid, nil, nil); err != nil {\n    if strings.Contains(err.Error(), \"acp: no agent session id\") {\n        ns, rerr := agent.StartSession(ctx, id, nil)\n        if rerr != nil { return rerr }\n        return ns.Send(prompt, mid, nil, nil)\n    }\n    return err\n}","preventionTips":["Always check the error from StartSession before using the session.","Never construct ACP sessions manually; use the library's StartSession so handshake runs.","Investigate any upstream empty-sessionId problem (error 45) that leaves the id unset."],"tags":["acp","session","missing-identifier","internal-state"],"backgroundTag":"missing-required-argument","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"}