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
- Retry the token request after a delay with exponential backoff, ideally when connectivity is confirmed available
- Use a ConnectivityManager NetworkCallback to wait for an active network before calling getToken
- Check that Google Play Services is running and up to date; restart the device if the service is wedged
- 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
- Register tokens from a background job with retry policy, not synchronously at startup
- Wait for network availability before calling getToken
- Avoid blocking user-facing flows on registration RPCs
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.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ERROR_BACKOFF
- (String) res
- ERROR_SERVICE_NOT_AVAILABLE
- duration limit reached (expired at ${request.expirationTime}
- deleteAll was set to true but keys were also provided
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/99624c6c3cd43ffd.
Report an issue: GitHub.