{"record":{"id":"830acc75b4c22705","repo":"chenhg5/cc-connect","slug":"opencode-parse-session-list-w","errorCode":null,"errorMessage":"opencode: parse session list: %w","messagePattern":"opencode: parse session list: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/opencode/opencode.go","lineNumber":637,"sourceCode":"type opencodeSessionEntry struct {\n\tID      string `json:\"id\"`\n\tTitle   string `json:\"title\"`\n\tUpdated int64  `json:\"updated\"` // Unix timestamp in milliseconds\n\tCreated int64  `json:\"created\"`\n}\n\nfunc listOpencodeSessions(cmd, workDir string) ([]core.AgentSessionInfo, error) {\n\tc := exec.Command(cmd, \"session\", \"list\", \"--format\", \"json\")\n\tc.Dir = workDir\n\n\tout, err := c.Output()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"opencode: session list: %w\", err)\n\t}\n\n\tvar entries []opencodeSessionEntry\n\tif err := json.Unmarshal(out, &entries); err != nil {\n\t\treturn nil, fmt.Errorf(\"opencode: parse session list: %w\", err)\n\t}\n\n\tmsgCounts := querySessionMessageCounts()\n\n\tvar sessions []core.AgentSessionInfo\n\tfor _, e := range entries {\n\t\tsessions = append(sessions, core.AgentSessionInfo{\n\t\t\tID:           e.ID,\n\t\t\tSummary:      e.Title,\n\t\t\tMessageCount: msgCounts[e.ID],\n\t\t\tModifiedAt:   time.UnixMilli(e.Updated),\n\t\t})\n\t}\n\n\treturn sessions, nil\n}\n\n// querySessionMessageCounts uses the sqlite3 CLI to read message counts from","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/opencode/opencode.go#L619-L655","documentation":"After successfully running `opencode session list --format json`, listOpencodeSessions unmarshals the stdout into []opencodeSessionEntry; if json.Unmarshal fails, the error is wrapped as `opencode: parse session list: %w`. This means the CLI ran but produced output that does not match the expected JSON array shape — usually an output-shape/version mismatch.","triggerScenarios":"The installed opencode version emits a different JSON schema (renamed fields, object instead of array); the CLI prints warnings/banners mixed into stdout; an empty or truncated output when stdout capture races process teardown; locale/encoding issues corrupting bytes.","commonSituations":"Upgrading opencode to a version whose session list schema changed while the adapter still expects the old shape; shell profile scripts printing text on non-interactive invocations; piping through a wrapper that injects extra output.","solutions":["Dump the raw output (`opencode session list --format json | jq .`) and compare field names with the opencodeSessionEntry struct in agent/opencode/opencode.go; update the struct tags to match the installed CLI version.","Pin opencode to a CLI version compatible with this cc-connect release.","Silence any shell profiles/banners that print to stdout for non-interactive shells.","Defensively trim/validate the output before unmarshal and surface the first bytes in the wrapped error for diagnosis."],"exampleFix":"// before\nvar entries []opencodeSessionEntry\nif err := json.Unmarshal(out, &entries); err != nil {\n    return nil, fmt.Errorf(\"opencode: parse session list: %w\", err)\n}\n\n// after\nvar entries []opencodeSessionEntry\nif err := json.Unmarshal(bytes.TrimSpace(out), &entries); err != nil {\n    return nil, fmt.Errorf(\"opencode: parse session list: %w (raw=%q)\", err, bytes.TrimSpace(out))\n}","handlingStrategy":"type-guard","validationCode":"// validate output shape before unmarshal\nout, err := runSessionList()\nif err != nil { return err }\ntrimmed := bytes.TrimSpace(out)\nif len(trimmed) == 0 || trimmed[0] != '[' {\n    return fmt.Errorf(\"unexpected session list output: %q\", trimmed)\n}","typeGuard":"func looksLikeSessionArray(out []byte) bool {\n    t := bytes.TrimSpace(out)\n    return bytes.HasPrefix(t, []byte(\"[\"))\n}","tryCatchPattern":"var entries []opencodeSessionEntry\nif err := json.Unmarshal(bytes.TrimSpace(out), &entries); err != nil {\n    return fmt.Errorf(\"opencode: parse session list: %w (raw=%q)\", err, bytes.TrimSpace(out))\n}","preventionTips":["Pin the opencode CLI version; re-check opencodeSessionEntry field tags whenever the CLI is upgraded","Strip banners/wrapper output so stdout contains only JSON","Use `opencode session list --format json | jq .` in CI smoke tests to catch schema drift early","Log a raw-output snippet with parse errors to speed up diagnosis"],"tags":["go","json","cli","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-14T00:17:10.932Z"}