{"record":{"id":"a7268ece1506ce62","repo":"microg/GmsCore","slug":"error-service-not-available-a7268e","errorCode":"ERROR_SERVICE_NOT_AVAILABLE","errorMessage":"ERROR_SERVICE_NOT_AVAILABLE","messagePattern":"ERROR_SERVICE_NOT_AVAILABLE","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdRpc.java","lineNumber":395,"sourceCode":"        }\n\n        sendRegisterMessage(data, keyPair, requestId);\n\n        cv.block(BLOCKING_WAIT_TIME);\n        synchronized (InstanceIdRpc.class) {\n            Object res = blockingResponses.remove(requestId);\n            if (res instanceof Intent) {\n                return (Intent) res;\n            } else if (res instanceof String) {\n                throw new IOException((String) res);\n            }\n            Log.w(TAG, \"No response \" + res);\n            throw new IOException(ERROR_TIMEOUT);\n        }\n    }\n\n    public String handleRegisterMessageResult(Intent resultIntent) throws IOException {\n        if (resultIntent == null) throw new IOException(ERROR_SERVICE_NOT_AVAILABLE);\n        String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);\n        if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);\n        if (result != null) return result;\n        result = resultIntent.getStringExtra(EXTRA_ERROR);\n        throw new IOException(result != null ? result : ERROR_SERVICE_NOT_AVAILABLE);\n    }\n\n    private void setResponse(String requestId, Object response) {\n        if (requestId == null) {\n            for (String r : blockingResponses.keySet()) {\n                setResponse(r, response);\n            }\n        }\n        Object old = blockingResponses.get(requestId);\n        blockingResponses.put(requestId, response);\n        if (old instanceof ConditionVariable) {\n            ((ConditionVariable) old).open();\n        } else if (old instanceof Messenger) {","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdRpc.java#L377-L413","documentation":"handleRegisterMessageResult throws ERROR_SERVICE_NOT_AVAILABLE when the registration result Intent is null — the service never delivered a usable reply. This signals the registration endpoint/service could not be reached or failed to respond with a result.","triggerScenarios":"handleRegisterMessageResult is invoked with a null resultIntent, typically from the broadcast/onHandleIntent path that receives the C2DM register reply when the reply Intent was never received (device offline, service unavailable, GMS hiccup).","commonSituations":"GCM/FCM registration during network outages; devices in Doze or with radios off; Play Services crash or update in progress; long-standing GCM issue where broadcasts are silently dropped.","solutions":["Retry registration with exponential backoff — this error is usually transient","Verify device connectivity before retrying (register a ConnectivityManager callback)","Ensure Google Play Services is installed, enabled, and up to date","Fall back to deferred registration (WorkManager retry policy) so tokens are fetched once connectivity returns"],"exampleFix":"// before\nString token = rpc.handleRegisterMessageResult(intent);\n// after\ntry {\n    String token = rpc.handleRegisterMessageResult(intent);\n} catch (IOException e) {\n    if (\"ERROR_SERVICE_NOT_AVAILABLE\".equals(e.getMessage())) {\n        workManagerEnqueueRetry(); // retry with backoff when online\n    }\n}","handlingStrategy":"retry","validationCode":"if (resultIntent == null) scheduleRetryWithBackoff(); // mimic library check upstream","typeGuard":null,"tryCatchPattern":"try {\n    String token = rpc.handleRegisterMessageResult(intent);\n} catch (IOException e) {\n    if (\"ERROR_SERVICE_NOT_AVAILABLE\".equals(e.getMessage())) {\n        retryWithExponentialBackoff();\n    }\n}","preventionTips":["Treat this as transient: implement idempotent retry with backoff","Defer registration until the device has connectivity","Register tokens in WorkManager jobs that survive process death"],"tags":["android","service-unavailable","registration","transient"],"backgroundTag":"http-error-response","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}