chenhg5/cc-connect · error

opencode: parse session list: %w

Error message

opencode: parse session list: %w

What it means

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.

Source

Thrown at agent/opencode/opencode.go:637

type opencodeSessionEntry struct {
	ID      string `json:"id"`
	Title   string `json:"title"`
	Updated int64  `json:"updated"` // Unix timestamp in milliseconds
	Created int64  `json:"created"`
}

func listOpencodeSessions(cmd, workDir string) ([]core.AgentSessionInfo, error) {
	c := exec.Command(cmd, "session", "list", "--format", "json")
	c.Dir = workDir

	out, err := c.Output()
	if err != nil {
		return nil, fmt.Errorf("opencode: session list: %w", err)
	}

	var entries []opencodeSessionEntry
	if err := json.Unmarshal(out, &entries); err != nil {
		return nil, fmt.Errorf("opencode: parse session list: %w", err)
	}

	msgCounts := querySessionMessageCounts()

	var sessions []core.AgentSessionInfo
	for _, e := range entries {
		sessions = append(sessions, core.AgentSessionInfo{
			ID:           e.ID,
			Summary:      e.Title,
			MessageCount: msgCounts[e.ID],
			ModifiedAt:   time.UnixMilli(e.Updated),
		})
	}

	return sessions, nil
}

// querySessionMessageCounts uses the sqlite3 CLI to read message counts from

View on GitHub (pinned to 4000b2338a)

Solutions

  1. 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.
  2. Pin opencode to a CLI version compatible with this cc-connect release.
  3. Silence any shell profiles/banners that print to stdout for non-interactive shells.
  4. Defensively trim/validate the output before unmarshal and surface the first bytes in the wrapped error for diagnosis.

Example fix

// before
var entries []opencodeSessionEntry
if err := json.Unmarshal(out, &entries); err != nil {
    return nil, fmt.Errorf("opencode: parse session list: %w", err)
}

// after
var entries []opencodeSessionEntry
if err := json.Unmarshal(bytes.TrimSpace(out), &entries); err != nil {
    return nil, fmt.Errorf("opencode: parse session list: %w (raw=%q)", err, bytes.TrimSpace(out))
}
Defensive patterns

Strategy: type-guard

Validate before calling

// validate output shape before unmarshal
out, err := runSessionList()
if err != nil { return err }
trimmed := bytes.TrimSpace(out)
if len(trimmed) == 0 || trimmed[0] != '[' {
    return fmt.Errorf("unexpected session list output: %q", trimmed)
}

Type guard

func looksLikeSessionArray(out []byte) bool {
    t := bytes.TrimSpace(out)
    return bytes.HasPrefix(t, []byte("["))
}

Try / catch

var entries []opencodeSessionEntry
if err := json.Unmarshal(bytes.TrimSpace(out), &entries); err != nil {
    return fmt.Errorf("opencode: parse session list: %w (raw=%q)", err, bytes.TrimSpace(out))
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/830acc75b4c22705. Report an issue: GitHub.