{"record":{"id":"570764411e4b0cd1","repo":"glanceapp/glance","slug":"unknown-operation-name-s","errorCode":null,"errorMessage":"unknown operation name: %s","messagePattern":"unknown operation name: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-twitch-channels.go","lineNumber":165,"sourceCode":"\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}\n\t}\n\n\tif channelShell.UserOrError.Type != \"User\" {\n\t\tresult.Name = result.Login\n\t\treturn result, nil\n\t}\n\n\tresult.Exists = true\n\tresult.Name = channelShell.UserOrError.DisplayName\n\tresult.AvatarUrl = channelShell.UserOrError.ProfileImageUrl\n\n\tif channelShell.UserOrError.Stream != nil {\n\t\tresult.IsLive = true\n\t\tresult.ViewersCount = channelShell.UserOrError.Stream.ViewersCount\n\n\t\tif streamMetadata.UserOrNull != nil && streamMetadata.UserOrNull.Stream != nil {\n\t\t\tif streamMetadata.UserOrNull.LastBroadcast != nil {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-twitch-channels.go#L147-L183","documentation":"The switch over response[i].Extensions.OperationName hit its default case: the GQL response contained an operation name other than the two expected ('ChannelShell', 'StreamMetadata'). Twitch either added an operation to the persisted batch, renamed one, or returned an error envelope whose operation name is unrecognized.","triggerScenarios":"Twitch adds a third operation to the batched persisted query, renames an operation, or the persisted query hash resolves to a different set of operations than the code was built for.","commonSituations":"Version skew: an old persisted-query hash still accepted but returning different operations; Twitch experimenting with the channel page query set; all Twitch channel lookups fail at once.","solutions":["Log the full Extensions of the unexpected operation to see what Twitch returned","Update the persisted query payload and the switch cases in internal/glance/widget-twitch-channels.go to handle the new operation name (or ignore unknown ones instead of failing)","Upgrade Glance to a release matching the current Twitch GQL contract"],"exampleFix":"// before\ndefault:\n    return result, fmt.Errorf(\"unknown operation name: %s\", response[i].Extensions.OperationName)\n\n// after (skip operations we don't consume)\ndefault:\n    slog.Warn(\"Unknown twitch GQL operation\", \"op\", response[i].Extensions.OperationName)\n    continue","handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isKnownOperation(name string) bool {\n\treturn name == \"ChannelShell\" || name == \"StreamMetadata\"\n}","tryCatchPattern":"result, err := fetchChannel(login)\nif err != nil && strings.HasPrefix(err.Error(), \"unknown operation name\") {\n    // skip unknown operations instead of failing the whole widget (requires code change)\n    slog.Warn(\"ignoring unknown twitch operation\", \"err\", err)\n}","preventionTips":["Treat unknown operation names as skippable, not fatal, when patching the widget","Validate operation names against a whitelist before unmarshalling"],"tags":["twitch","api-change","widget","contract-change"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}