{"record":{"id":"8ebdcc3cedd4793c","repo":"microg/GmsCore","slug":"familyresponse-is-null","errorCode":null,"errorMessage":"familyResponse is null","messagePattern":"familyResponse is null","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/model/FamilyViewModel.kt","lineNumber":104,"sourceCode":"\n    fun loadFamilyMembers(context: Context, accountName: String, appId: String, flag: Int = FAMILY_PAGE_CONTENT_FLAG_MEMBER_LIST) {\n        viewModelScope.launch {\n            supervisorScope {\n                runCatching {\n                    _uiState.update { it.copy(isLoading = true, isError = false) }\n                    val oauthToken = requestOauthToken(context, accountName, SERVICE_FAMILY_SCOPE)\n                    val familyResponseDeferred = async {\n                        FamilyApiClient.loadFamilyData(context, oauthToken, appId, flag)\n                    }\n                    val configResponseDeferred = async {\n                        FamilyApiClient.loadFamilyManagementConfig(context, oauthToken, appId, false)\n                    }\n                    val familyResponse = familyResponseDeferred.await()\n                    val configResponse = configResponseDeferred.await()\n                    Log.d(TAG, \"loadFamilyMembers: familyResponse: $familyResponse\")\n                    Log.d(TAG, \"loadFamilyMembers: configResponse: $configResponse\")\n                    familyResponse?.parseToMemberDataModels(context, accountName, configResponse)\n                        ?: throw RuntimeException(\"familyResponse is null\")\n                }.onFailure { throwable ->\n                    _familyChangedStateState.value = FamilyChangedState.Error(throwable.message ?: \"\", 4)\n                    _uiState.update { it.copy(isLoading = false, isError = true) }\n                    Log.d(TAG, \"loadFamilyMembers error\", throwable)\n                }.onSuccess { list ->\n                    _uiState.update {\n                        it.copy(\n                            isLoading = false,\n                            memberList = list,\n                            currentMember = list.firstOrNull { m -> m.email == accountName } ?: MemberDataModel()\n                        )\n                    }\n                }\n            }\n        }\n    }\n\n    fun loadFamilyManagementPageContent(","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-core/src/main/kotlin/com/google/android/gms/family/v2/manage/model/FamilyViewModel.kt#L86-L122","documentation":"FamilyViewModel.loadFamilyMembers throws RuntimeException(\"familyResponse is null\") when the deferred network call for GetFamilyResponse completes but yields null, so member data models cannot be parsed. This null-guard converts an empty/failed API result into an explicit error state in the UI.","triggerScenarios":"The family members API call returns a null body — e.g. the account has no family group, the server returned an empty/error response, or the client wrapper maps failures to null instead of throwing.","commonSituations":"Opening family management for an account with no family set up, expired oauth token causing an empty response, or backend outage returning null payloads.","solutions":["Check the API call and its error channel before awaiting; surface HTTP/auth failures distinctly instead of null","Handle the no-family-group case as a valid empty state rather than an error","Ensure requestOauthToken succeeded and the token is valid before the family request","Catch the error (onFailure already sets FamilyChangedState.Error) and offer retry / sign-in flow"],"exampleFix":"// before\nval familyResponse = familyResponseDeferred.await()\nfamilyResponse?.parseToMemberDataModels(...) ?: throw RuntimeException(\"familyResponse is null\")\n// after\nval familyResponse = familyResponseDeferred.await()\nval members = familyResponse?.parseToMemberDataModels(...)\nif (members == null) {\n    _familyChangedStateState.value = FamilyChangedState.Empty\n    return@runCatching\n}","handlingStrategy":"type-guard","validationCode":"val familyResponse = familyResponseDeferred.await()\nif (familyResponse == null) {\n    _familyChangedStateState.value = FamilyChangedState.Empty\n    return@runCatching\n}","typeGuard":"fun <T> Deferred<T?>.awaitOrNull(): T? = try { await() } catch (e: Exception) { null }\n// usage: if (familyResponseDeferred.awaitOrNull() == null) treat as empty/error","tryCatchPattern":"runCatching {\n    val resp = familyResponseDeferred.await()\n        ?: throw RuntimeException(\"familyResponse is null\")\n}.onFailure { t -> showFamilyError(t) }","preventionTips":["Distinguish 'no family group' empty states from hard errors","Ensure oauth token acquisition succeeds before the family request","Log raw API responses to detect empty bodies early"],"tags":["android","viewmodel","null-safety","network"],"backgroundTag":"empty-api-response","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}