{"record":{"id":"23d6af6378f8875e","repo":"chenhg5/cc-connect","slug":"acp-parse-session-new-w","errorCode":null,"errorMessage":"acp: parse session/new: %w","messagePattern":"acp: parse session/new: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/acp/session.go","lineNumber":243,"sourceCode":"\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\n\tnewParams := map[string]any{\n\t\t\"cwd\":        s.workDir,\n\t\t\"mcpServers\": []any{},\n\t}\n\tnewRes, err := s.tr.call(s.ctx, \"session/new\", newParams)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acp: session/new: %w\", err)\n\t}\n\tvar sn struct {\n\t\tSessionID string         `json:\"sessionId\"`\n\t\tModes     *acpModesBlock `json:\"modes\"`\n\t}\n\tif err := json.Unmarshal(newRes, &sn); err != nil {\n\t\treturn fmt.Errorf(\"acp: parse session/new: %w\", err)\n\t}\n\tif sn.SessionID == \"\" {\n\t\treturn fmt.Errorf(\"acp: session/new: empty sessionId\")\n\t}\n\ts.setACPSessionID(sn.SessionID)\n\ts.absorbModes(sn.Modes)\n\treturn nil\n}\n\n// absorbModes copies a modes block into the session's cache and fans\n// it out to the parent agent callbacks (if any). Both the session and\n// the agent need the information: the session uses it to validate\n// SetLiveMode inputs; the agent uses it to render `/mode` menus in IM.\nfunc (s *acpSession) absorbModes(block *acpModesBlock) {\n\tif block == nil || len(block.AvailableModes) == 0 {\n\t\treturn\n\t}\n\ts.modesMu.Lock()","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/acp/session.go#L225-L261","documentation":"Wrapped when the `session/new` JSON-RPC result cannot be unmarshalled into the expected shape ({sessionId, modes}). The agent answered session/new but the payload is malformed, so no session id can be cached and the handshake fails.","triggerScenarios":"The agent's session/new result is not the expected JSON object — missing/mis-typed `sessionId`, wrong field names (e.g. `id` instead of `sessionId`), or non-JSON body — causing json.Unmarshal to fail.","commonSituations":"Agent speaks a divergent ACP dialect with different field casing/names; a middleware rewrites or truncates the response; agent version skew with the client's expected schema.","solutions":["Dump the raw newRes payload to compare against the expected {sessionId, modes} schema.","Upgrade the agent (or cc-connect) so both sides use the same ACP schema version.","If the agent uses a different field name for the session id, wrap/normalize the response in the transport before unmarshal.","Remove any proxy/transform layer between cc-connect and the agent that could alter the JSON."],"exampleFix":"// agent replying {\"id\": \"s_1\"} instead of {\"sessionId\": \"s_1\"}\n// after: use an agent build that returns {\"sessionId\": \"s_1\", \"modes\": {...}}","handlingStrategy":"try-catch","validationCode":"// pre-validate session/new response shape before trusting it\nvar probe struct{ SessionID string `json:\"sessionId\"` }\nif err := json.Unmarshal(newRes, &probe); err != nil {\n    return fmt.Errorf(\"agent session/new payload non-conforming\")\n}","typeGuard":null,"tryCatchPattern":"sess, err := agent.StartSession(ctx, id, nil)\nif err != nil && strings.Contains(err.Error(), \"parse session/new\") {\n    slog.Error(\"agent session/new schema mismatch — likely version skew\", \"err\", err)\n    return err\n}","preventionTips":["Match cc-connect and agent ACP schema versions.","Capture the raw session/new response in debug logs for schema debugging.","Remove middleware that mutates JSON-RPC responses."],"tags":["acp","handshake","json-unmarshal","schema"],"backgroundTag":"json-unmarshal-failed","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"}