microg/GmsCore · error · IllegalArgumentException
Invalid topic:
Error message
Invalid topic:
What it means
GcmPubSub.subscribe throws IllegalArgumentException when the topic is empty or does not match the required pattern "/topics/[a-zA-Z0-9-_.~%]{1,900}". Topics must start with the literal prefix "/topics/" followed only by allowed characters, up to 900 chars.
Source
Thrown at play-services-gcm/src/main/java/com/google/android/gms/gcm/GcmPubSub.java:93
* The topic sender must be authorized to send messages to the
* app instance. To authorize it, call {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}
* with the sender ID and {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE}
* <p/>
* Do not call this function on the main thread.
*
* @param registrationToken {@link com.google.android.gms.iid.InstanceID} token that authorizes topic
* sender to send messages to the app instance.
* @param topic developer defined topic name.
* Must match the following regular expression:
* "/topics/[a-zA-Z0-9-_.~%]{1,900}".
* @param extras (optional) additional information.
* @throws IOException if the request fails.
*/
public void subscribe(String registrationToken, String topic, Bundle extras) throws IOException {
if (TextUtils.isEmpty(registrationToken))
throw new IllegalArgumentException("No registration token!");
if (TextUtils.isEmpty(topic) || !topicPattern.matcher(topic).matches())
throw new IllegalArgumentException("Invalid topic: " + topic);
if (extras == null) extras = new Bundle();
extras.putString(EXTRA_TOPIC, topic);
instanceId.getToken(registrationToken, topic, extras);
}
/**
* Unsubscribes an app instance from a topic, stopping it from receiving
* any further messages sent to that topic.
* <p/>
* Do not call this function on the main thread.
*
* @param registrationToken {@link com.google.android.gms.iid.InstanceID} token
* for the same sender and scope that was previously
* used for subscribing to the topic.
* @param topic from which to stop receiving messages.
* @throws IOException if the request fails.
*/View on GitHub (pinned to 157c9d86ac)
Solutions
- Format the topic as "/topics/" + name, using only [a-zA-Z0-9-_.~%] characters in the name.
- Sanitize/normalize user- or server-provided topic names before subscribing.
- Validate with a regex before calling: topic.matches("/topics/[a-zA-Z0-9-_.~%]{1,900}").
Example fix
// before
pubSub.subscribe(token, "news", null); // Invalid topic: news
// after
String topic = "/topics/news"; // matches /topics/[a-zA-Z0-9-_.~%]{1,900}
pubSub.subscribe(token, topic, null); Defensive patterns
Strategy: validation
Validate before calling
private static final Pattern TOPIC = Pattern.compile("/topics/[a-zA-Z0-9-_.~%]{1,900}");
boolean isValidTopic(String t) { return t != null && TOPIC.matcher(t).matches(); } Try / catch
try {
pubSub.subscribe(token, topic, null);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Invalid topic: " + e.getMessage());
} Prevention
- Always prefix topic names with "/topics/"
- Restrict topic names to [a-zA-Z0-9-_.~%]
- Validate topics at creation time, before they reach subscribe
When it happens
Trigger: Calling subscribe(token, topic, extras) with topic like "news" (missing /topics/ prefix), containing spaces, slashes, unicode, or an empty string.
Common situations: Passing a raw topic name without the /topics/ prefix; building the topic from user input containing illegal characters; topic longer than 900 characters after prefixing.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/7f9b0232a19c1f7a.
Report an issue: GitHub.