microg/GmsCore · error · IOException

ERROR_TIMEOUT

ERROR_TIMEOUT

Error message

ERROR_TIMEOUT

What it means

sendRegisterMessageBlockingInternal throws ERROR_TIMEOUT when, after BLOCKING_WAIT_TIME elapses, no response (Intent or error String) was recorded for the request in blockingResponses. The registration RPC never completed in time, so the pending waiter gives up with this IOException.

Source

Thrown at play-services-iid/src/main/java/org/microg/gms/iid/InstanceIdRpc.java:390

    private Intent sendRegisterMessageBlockingInternal(Bundle data, KeyPair keyPair) throws IOException {
        ConditionVariable cv = new ConditionVariable();
        String requestId = getRequestId();
        synchronized (InstanceIdRpc.class) {
            blockingResponses.put(requestId, cv);
        }

        sendRegisterMessage(data, keyPair, requestId);

        cv.block(BLOCKING_WAIT_TIME);
        synchronized (InstanceIdRpc.class) {
            Object res = blockingResponses.remove(requestId);
            if (res instanceof Intent) {
                return (Intent) res;
            } else if (res instanceof String) {
                throw new IOException((String) res);
            }
            Log.w(TAG, "No response " + res);
            throw new IOException(ERROR_TIMEOUT);
        }
    }

    public String handleRegisterMessageResult(Intent resultIntent) throws IOException {
        if (resultIntent == null) throw new IOException(ERROR_SERVICE_NOT_AVAILABLE);
        String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);
        if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);
        if (result != null) return result;
        result = resultIntent.getStringExtra(EXTRA_ERROR);
        throw new IOException(result != null ? result : ERROR_SERVICE_NOT_AVAILABLE);
    }

    private void setResponse(String requestId, Object response) {
        if (requestId == null) {
            for (String r : blockingResponses.keySet()) {
                setResponse(r, response);
            }
        }

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Retry the token request after a delay with exponential backoff, ideally when connectivity is confirmed available
  2. Use a ConnectivityManager NetworkCallback to wait for an active network before calling getToken
  3. Check that Google Play Services is running and up to date; restart the device if the service is wedged
  4. Increase resilience by registering tokens in a background job (WorkManager/JobScheduler) rather than blocking user-facing code

Example fix

// before
String token = instanceId.getToken(senderId, "GCM");
// after
retryWithBackoff(5, 500, () -> {
    try { return instanceId.getToken(senderId, "GCM"); }
    catch (IOException e) {
        if ("ERROR_TIMEOUT".equals(e.getMessage())) return null; // retry
        throw e;
    }
});
Defensive patterns

Strategy: retry

Validate before calling

NetworkInfo net = cm.getActiveNetworkInfo();
if (net == null || !net.isConnected()) deferRegistrationUntilOnline();

Try / catch

try {
    String token = instanceId.getToken(senderId, "GCM");
} catch (IOException e) {
    if ("ERROR_TIMEOUT".equals(e.getMessage())) {
        enqueueRetryWithBackoff(); // e.g. WorkManager
    }
}

Prevention

When it happens

Trigger: Calling getToken while the device is offline or the Play Services registration service is unresponsive; the reply broadcast to the C2DM_REGISTER intent is lost or delayed beyond BLOCKING_WAIT_TIME; the target service process crashes before answering.

Common situations: Poor or flaky mobile connectivity during app startup token fetch; devices where Play Services is busy or just updated; emulators without network access; microG setups whose push connection is not yet established.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/99624c6c3cd43ffd. Report an issue: GitHub.