{"record":{"id":"f79206295cc6e125","repo":"glanceapp/glance","slug":"expected-2-operation-responses-got-d","errorCode":null,"errorMessage":"expected 2 operation responses, got %d","messagePattern":"expected 2 operation responses, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-twitch-channels.go","lineNumber":148,"sourceCode":"// what the limit is for max operations per request and batch operations in\n// multiple requests if number of channels exceeds allowed limit.\n\nfunc fetchChannelFromTwitchTask(channel string) (twitchChannel, error) {\n\tresult := twitchChannel{\n\t\tLogin: strings.ToLower(channel),\n\t}\n\n\treader := strings.NewReader(fmt.Sprintf(twitchChannelStatusOperationRequestBody, channel, channel))\n\trequest, _ := http.NewRequest(\"POST\", twitchGqlEndpoint, reader)\n\trequest.Header.Add(\"Client-ID\", twitchGqlClientId)\n\n\tresponse, err := decodeJsonFromRequest[[]twitchOperationResponse](defaultHTTPClient, request)\n\tif err != nil {\n\t\treturn result, err\n\t}\n\n\tif len(response) != 2 {\n\t\treturn result, fmt.Errorf(\"expected 2 operation responses, got %d\", len(response))\n\t}\n\n\tvar channelShell twitchChannelShellOperationResponse\n\tvar streamMetadata twitchStreamMetadataOperationResponse\n\n\tfor i := range response {\n\t\tswitch response[i].Extensions.OperationName {\n\t\tcase \"ChannelShell\":\n\t\t\tif err = json.Unmarshal(response[i].Data, &channelShell); err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"unmarshalling channel shell: %w\", err)\n\t\t\t}\n\t\tcase \"StreamMetadata\":\n\t\t\tif err = json.Unmarshal(response[i].Data, &streamMetadata); err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"unmarshalling stream metadata: %w\", err)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn result, fmt.Errorf(\"unknown operation name: %s\", response[i].Extensions.OperationName)\n\t\t}","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-twitch-channels.go#L130-L166","documentation":"Returned by the Twitch channels widget (internal/glance/widget-twitch-channels.go:148) when the batched GraphQL request to Twitch's GQL endpoint (two operations in one POST body: ChannelShell + StreamMetadata, both for the same channel name) decoded successfully as JSON but did not yield exactly 2 operation responses. Twitch acknowledged the request but returned a different number of operations — typically 0 (error envelope) or 1 (one operation dropped/failed server-side).","triggerScenarios":"POST to twitchGqlEndpoint with the two-operation body returning [] or a single-element array: Twitch GQL errors on the batch (invalid channel name, renamed/deleted channel), a GQL syntax/schema change collapsing the batch, or an error response shape that decodes as a short array instead of the expected pair.","commonSituations":"Channel renamed or suspended so ChannelShell/StreamMetadata ops fail; Twitch changing their undocumented GQL schema after a Glance release (these errors arrive in waves, like the Reddit ones); special characters in the channel field.","solutions":["Update Glance — Twitch GQL breakage is fixed upstream when Twitch changes shapes","Verify the channel exists and its exact current name at twitch.tv","Remove or correct the failing channel entry; sibling channels in the widget continue independently","Report upstream with the channel name and Glance version if the channel is valid"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Verify channel exists before adding it (public API)\nresp, _ := http.Get(\"https://www.twitch.tv/\" + channel)\n// non-200 => GQL batch will likely fail","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"expected 2 operation responses\") {\n    // Twitch GQL shape drift or bad channel; retry later, update Glance\n}","preventionTips":["Track channels by their exact current names","Update Glance when Twitch changes its GQL schema","Isolate suspicious channels to identify the offender"],"tags":["twitch","graphql","api-change","channels"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}