glanceapp/glance · error
unmarshalling channel shell: %w
Error message
unmarshalling channel shell: %w
What it means
Emitted while parsing the 'ChannelShell' part of a Twitch GQL (private GraphQL) batched response in the twitch-channels widget. The widget posts two persisted operations (ChannelShell, StreamMetadata) and json.Unmarshal of the ChannelShell payload into twitchChannelShellOperationResponse failed. It almost always means Twitch changed the shape of that operation's data without notice, since the GQL endpoint is undocumented.
Source
Thrown at internal/glance/widget-twitch-channels.go:158
request.Header.Add("Client-ID", twitchGqlClientId)
response, err := decodeJsonFromRequest[[]twitchOperationResponse](defaultHTTPClient, request)
if err != nil {
return result, err
}
if len(response) != 2 {
return result, fmt.Errorf("expected 2 operation responses, got %d", len(response))
}
var channelShell twitchChannelShellOperationResponse
var streamMetadata twitchStreamMetadataOperationResponse
for i := range response {
switch response[i].Extensions.OperationName {
case "ChannelShell":
if err = json.Unmarshal(response[i].Data, &channelShell); err != nil {
return result, fmt.Errorf("unmarshalling channel shell: %w", err)
}
case "StreamMetadata":
if err = json.Unmarshal(response[i].Data, &streamMetadata); err != nil {
return result, fmt.Errorf("unmarshalling stream metadata: %w", err)
}
default:
return result, fmt.Errorf("unknown operation name: %s", response[i].Extensions.OperationName)
}
}
if channelShell.UserOrError.Type != "User" {
result.Name = result.Login
return result, nil
}
result.Exists = true
result.Name = channelShell.UserOrError.DisplayName
result.AvatarUrl = channelShell.UserOrError.ProfileImageUrlView on GitHub (pinned to 91324e8de7)
Solutions
- Capture the raw response body and diff it against twitchChannelShellOperationResponse to find the changed field
- Update the struct in internal/glance/widget-twitch-channels.go to match the new payload (or relax field types, e.g. json.Number / pointers)
- Upgrade Glance to the latest release, which usually pins a fixed persisted query hash and structs
- If broken in your fork, verify the persistedQuery hash still resolves; a stale hash can return an error object instead of the expected data
Example fix
// before
if err = json.Unmarshal(response[i].Data, &channelShell); err != nil {
return result, fmt.Errorf("unmarshalling channel shell: %w", err)
}
// after (diagnose shape drift)
if err = json.Unmarshal(response[i].Data, &channelShell); err != nil {
slog.Error("ChannelShell payload", "raw", string(response[i].Data))
return result, fmt.Errorf("unmarshalling channel shell: %w", err)
} Defensive patterns
Strategy: fallback
Type guard
func isTwitchUnmarshalErr(err error) bool {
var typeErr *json.UnmarshalTypeError
return errors.As(err, &typeErr)
} Try / catch
channels, err := widget.getChannels()
if err != nil {
if strings.Contains(err.Error(), "unmarshalling channel shell") {
// Twitch GQL schema drift: render degraded UI, log for maintainers
slog.Error("twitch schema mismatch", "err", err)
}
return err
} Prevention
- Pin a Glance version and upgrade promptly when Twitch ships breaking GQL changes
- Watch the repo's issues for 'Twitch widget broken' reports before debugging yourself
- Keep the persisted query hash in sync with the struct definitions when forking
When it happens
Trigger: A POST to gql.twitch.tv/gql with the ChannelShell persisted query whose Data no longer matches twitchChannelShellOperationResponse (renamed/removed fields with incompatible types, or Data being null/absent). Triggers on any channel lookup once the schema change rolls out.
Common situations: Twitch A/B tests or ships a layout/API change; users on older Glance builds suddenly see all Twitch channels fail with 'Failed to fetch Twitch channel'; Data null when a channel is suspended/deleted.
Related errors
- unmarshalling stream metadata: %w
- unknown operation name: %s
- no categories could be retrieved
- marshaling body: %v
- expected 2 operation responses, got %d
AI-assisted analysis of glanceapp/glance@91324e8de7 (2026-08-15).
Data as JSON: /api/errors/36afa9af441b6b0c.
Report an issue: GitHub.