{"record":{"id":"51422e6b25504230","repo":"microg/GmsCore","slug":"string-res","errorCode":null,"errorMessage":"(String) res","messagePattern":"\\(String\\) res","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdRpc.java","lineNumber":387,"sourceCode":"        return intent;\n    }\n\n    private Intent sendRegisterMessageBlockingInternal(Bundle data, KeyPair keyPair) throws IOException {\n        ConditionVariable cv = new ConditionVariable();\n        String requestId = getRequestId();\n        synchronized (InstanceIdRpc.class) {\n            blockingResponses.put(requestId, cv);\n        }\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()) {","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdRpc.java#L369-L405","documentation":"In sendRegisterMessageBlockingInternal, when the blocking response for a requestId is a plain String instead of an Intent, the library treats that string as an error message and rethrows it inside an IOException. The message here is the raw error string sent back by the registration service, e.g. ERROR_SERVICE_NOT_AVAILABLE or a service-specific code.","triggerScenarios":"The IID service (or microG's RPC receiver) delivered an error result via setResponse(requestId, errorMessage) for the pending request; the blocked thread wakes with a String payload and throws IOException(errorMessage).","commonSituations":"Server-side registration failures (quota, invalid sender); device connectivity problems mid-registration; Play Services returning structured error strings instead of result Intents; microG implementations mapping GMS errors to string responses.","solutions":["Catch the IOException and inspect getMessage() to branch on known codes (ERROR_SERVICE_NOT_AVAILABLE, ERROR_BACKOFF, etc.)","Retry with exponential backoff when the message is ERROR_SERVICE_NOT_AVAILABLE","Check network connectivity and Google Play Services availability before calling getToken","Log the raw message — a non-standard string often indicates a provider-side (GMS/microG) problem"],"exampleFix":"// before\nString token = instanceId.getToken(senderId, \"GCM\");\n// after\ntry {\n    String token = instanceId.getToken(senderId, \"GCM\");\n} catch (IOException e) {\n    if (\"ERROR_SERVICE_NOT_AVAILABLE\".equals(e.getMessage())) {\n        scheduleRetryWithBackoff();\n    } else {\n        Log.w(TAG, \"Registration failed: \" + e.getMessage());\n    }\n}","handlingStrategy":"try-catch","validationCode":"// ensure connectivity before registration\nif (!isNetworkAvailable(context)) deferRegistration();","typeGuard":null,"tryCatchPattern":"try {\n    String token = instanceId.getToken(senderId, \"GCM\");\n} catch (IOException e) {\n    String msg = e.getMessage();\n    if (msg != null && msg.startsWith(\"ERROR_\")) {\n        handleKnownIidError(msg); // branch per known code, retry if transient\n    } else {\n        logAndReport(msg); // provider-specific error\n    }\n}","preventionTips":["Log e.getMessage() verbatim to identify provider-side codes","Retry transient codes with backoff; surface config codes to the developer","Keep Play Services/microG updated"],"tags":["android","registration","rpc","play-services"],"backgroundTag":"api-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"}