chenhg5/cc-connect · error

session.create decode: %w

Error message

session.create decode: %w

What it means

After a successful 'session.create' RPC, createSession decodes the CLI's result payload expecting a JSON object with a 'sessionId' string field. If json.Unmarshal fails, the response was not the expected shape and the error is wrapped as 'session.create decode: %w'. This guards against protocol drift between cc-connect and the Copilot CLI.

Source

Thrown at agent/copilot/session.go:207

		}
	} else {
		return cs.createSession()
	}
	return nil
}

func (cs *copilotSession) createSession() error {
	_, createCh := cs.rpc.call("session.create", cs.sessionConfig(newCopilotSessionID()))
	select {
	case resp := <-createCh:
		if resp.Error != nil {
			return fmt.Errorf("session.create: %w", resp.Error)
		}
		var result struct {
			SessionID string `json:"sessionId"`
		}
		if err := json.Unmarshal(resp.Result, &result); err != nil {
			return fmt.Errorf("session.create decode: %w", err)
		}
		cs.sessionID.Store(result.SessionID)
		slog.Info("copilotSession: session created", "sessionId", result.SessionID)
	case <-time.After(10 * time.Second):
		return fmt.Errorf("session.create timeout")
	case <-cs.ctx.Done():
		return cs.ctx.Err()
	}
	return nil
}

func (cs *copilotSession) sessionConfig(sessionID string) copilotSessionConfig {
	requestPermission := true
	streaming := true
	includeSubAgentStreaming := true
	enableConfigDiscovery := true
	return copilotSessionConfig{
		SessionID:                      sessionID,

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the installed Copilot CLI version and pin/upgrade cc-connect (or the CLI) so both sides agree on the session.create result schema.
  2. Ensure nothing else writes to the child process's stdout (wrapper scripts, shell profiles echoing text).
  3. Log resp.Result raw JSON at the failure point to see the actual payload and compare with the expected struct.
  4. Retry once; a truncated pipe read can occasionally cause this.
  5. File an issue with the raw payload if a version pair consistently fails.

Example fix

// before: silent protocol mismatch
// (CLI returns {"id": "..."} instead of {"sessionId": "..."})
// after: pin a compatible CLI version
// .github/workflows/ci.yml or install script
copilot --version # verify compatibility; install the version cc-connect documents
Defensive patterns

Strategy: type-guard

Validate before calling

var probe map[string]any
if err := json.Unmarshal(rawResult, &probe); err != nil {
    return fmt.Errorf("session.create result not JSON: %w", err)
}
if _, ok := probe["sessionId"].(string); !ok {
    return fmt.Errorf("session.create result missing sessionId")
}

Type guard

func hasSessionID(result json.RawMessage) bool {
    var r struct{ SessionID string `json:"sessionId"` }
    return json.Unmarshal(result, &r) == nil && r.SessionID != ""
}

Try / catch

if err := agent.StartSession(ctx, opts); err != nil && strings.Contains(err.Error(), "session.create decode") {
    slog.Error("protocol mismatch with copilot CLI", "err", err)
    // report version pair and fail fast
}

Prevention

When it happens

Trigger: handshake -> createSession -> json.Unmarshal(resp.Result, &result) fails because the CLI returned a result payload without the expected {"sessionId": "..."} shape (protocol change, error payload in result position, empty/garbled JSON).

Common situations: Copilot CLI was updated and renamed/removed the sessionId result field; a proxy/wrapper prints extra output on stdout corrupting JSON-RPC framing; the CLI returned an error-shaped body inside Result.

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/e43db3c3d8194f8f. Report an issue: GitHub.