github/copilot-sdk · error

failed to unmarshal response

Error message

failed to unmarshal response: %w

What it means

After a successful session.create request, CreateSession unmarshals the result payload into createSessionResponse. This error wraps a json.Unmarshal failure, meaning the final result field of the response could not be decoded into the expected response struct. The request succeeded at transport level but the payload shape is unexpected.

Solutions

  1. Capture and inspect the raw result JSON returned by session.create
  2. Align server and SDK versions so the response schema matches createSessionResponse
  3. Fix test fixtures/mocks to emit JSON compatible with createSessionResponse
  4. Check for proxy middleware that rewrites or truncates response bodies

Example fix

// fixture before
{"sessionId": 123}
// after
{"sessionId": "sess_123"}
Defensive patterns

Strategy: validation

Validate before calling

var probe map[string]json.RawMessage
if err := json.Unmarshal(result, &probe); err != nil {
    return fmt.Errorf("non-object result: %s", string(result))
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to unmarshal response") {
    log.Printf("unexpected session.create result schema: %s", rawResult)
    return checkVersionSkew(err)
}

Prevention

When it happens

Trigger: session.create returns a successful result whose JSON does not match createSessionResponse's fields/types — e.g. sessionId as a number instead of string, or extra incompatible field types.

Common situations: Server/SDK version skew changing the response schema; a proxy mangling the body; tests with hand-written fixture responses that don't match the struct.

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 github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/121b29d99ed1047d. Report an issue: GitHub.

Appendix: source

Thrown at go/client.go:1152

			registeredSessionID = early.SessionID
			return nil
		}
	}

	result, err := c.client.RequestWithInlineResponse(ctx, "session.create", req, inlineCb)
	if err != nil {
		if registeredSessionID != "" {
			unregisterSession(registeredSessionID, session)
		}
		return nil, fmt.Errorf("failed to create session: %w", err)
	}

	var response createSessionResponse
	if err := json.Unmarshal(result, &response); err != nil {
		if registeredSessionID != "" {
			unregisterSession(registeredSessionID, session)
		}
		return nil, fmt.Errorf("failed to unmarshal response: %w", err)
	}

	if session == nil {
		return nil, fmt.Errorf("session.create response did not include a sessionId")
	}

	if localSessionID != "" && response.SessionID != "" && response.SessionID != localSessionID {
		unregisterSession(registeredSessionID, session)
		return nil, fmt.Errorf("session.create returned sessionId %s but the caller requested %s", response.SessionID, localSessionID)
	}
	if config.OnMCPAuthRequest != nil {
		if _, err := c.client.Request(ctx, "session.eventLog.registerInterest", map[string]any{
			"sessionId": session.SessionID,
			"eventType": "mcp.oauth_required",
		}); err != nil {
			unregisterSession(registeredSessionID, session)
			return nil, err
		}

View on GitHub (pinned to cd8cf15dc3)