github/copilot-sdk · error
failed to unmarshal models response
Error message
failed to unmarshal models response: %w
What it means
ListModels wraps a json.Unmarshal failure of the raw models.list RPC result with this error. The backend returned JSON that does not fit the expected listModelsResponse shape. It almost always indicates a server/SDK protocol or payload mismatch rather than a caller mistake.
Solutions
- Verify the CLI backend and SDK versions match; upgrade the SDK or server so the models response schema aligns.
- Log the raw result payload (before unmarshal) to see the actual JSON shape returned.
- Check for proxies/wrappers altering the response body between server and SDK.
- Update server to a version whose models.list response includes the expected fields (e.g. models array of ModelInfo).
Example fix
// before
var response listModelsResponse
if err := json.Unmarshal(result, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal models response: %w", err)
}
// after (debug the raw payload)
if err := json.Unmarshal(result, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal models response: %w (payload: %s)", err, truncate(result, 512))
} Defensive patterns
Strategy: validation
Validate before calling
// verify version compatibility before RPC
if client.GetNegotiatedProtocolVersion() == 0 {
return errors.New("handshake incomplete; payload schema may differ")
} Try / catch
models, err := client.ListModels(ctx)
var umErr *json.UnmarshalTypeError
if errors.As(err, &umErr) || strings.Contains(err.Error(), "failed to unmarshal models response") {
// log payload + versions, surface as protocol mismatch
return fmt.Errorf("protocol/schema mismatch: %w", err)
} Prevention
- Keep SDK and CLI/server versions aligned.
- Pin dependency versions in go.mod and upgrade together with the backend.
- Log raw RPC payloads on decode failure for diagnosis.
- Check for middleware/proxies rewriting response bodies.
When it happens
Trigger: The models.list RPC succeeds at the transport level but its result bytes cannot be decoded into listModelsResponse — e.g. server returns an object with different field names/types, a bare array, or truncated/non-JSON output.
Common situations: Mixing an older CLI binary with a newer SDK (or vice versa), a proxy injecting HTML error pages, or a server bug changing the models payload schema.
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
- failed to unmarshal get events response
- failed to decode session detach response
- failed to unmarshal schema for type
- failed to unmarshal response
- failed to unmarshal sessions response
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/310d13d6ceaf1fa0.
Report an issue: GitHub.
Appendix: source
Thrown at go/client.go:1946
// Use custom handler instead of CLI RPC
var err error
models, err = c.onListModels(ctx)
if err != nil {
return nil, err
}
} else {
if c.client == nil {
return nil, fmt.Errorf("client not connected")
}
// Cache miss - fetch from backend while holding lock
result, err := c.client.Request(ctx, "models.list", listModelsRequest{})
if err != nil {
return nil, err
}
var response listModelsResponse
if err := json.Unmarshal(result, &response); err != nil {
return nil, fmt.Errorf("failed to unmarshal models response: %w", err)
}
models = response.Models
}
// Update cache before releasing lock (copy to prevent external mutation)
cache := make([]ModelInfo, len(models))
copy(cache, models)
c.modelsCache = cache
// Return a copy to prevent cache mutation
result := make([]ModelInfo, len(models))
copy(result, models)
return result, nil
}
// minProtocolVersion is the minimum protocol version this SDK can communicate with.
const minProtocolVersion = 3
const runtimeShutdownTimeout = 10 * time.SecondView on GitHub (pinned to cd8cf15dc3)