microg/GmsCore · error · IllegalStateException

Network URL required

Error message

Network URL required

What it means

RemoteHandleImpl performs DroidGuard flows against a remote network server whose URL is read lazily from DroidGuardPreferences.getNetworkServerUrl(context). When no server URL is configured, the url property getter throws IllegalStateException('Network URL required') as soon as any operation needs the URL. The remote handle is useless without a configured endpoint, so the library fails fast instead of issuing a request to null.

Source

Thrown at play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/RemoteHandleImpl.kt:24

package org.microg.gms.droidguard.core

import android.content.Context
import android.net.Uri
import android.util.Base64
import com.google.android.gms.droidguard.internal.DroidGuardInitReply
import com.google.android.gms.droidguard.internal.DroidGuardResultsRequest
import com.google.android.gms.droidguard.internal.IDroidGuardHandle
import android.util.Log
import java.net.HttpURLConnection
import java.net.URL

private const val TAG = "RemoteGuardImpl"

class RemoteHandleImpl(private val context: Context, private val packageName: String) : IDroidGuardHandle.Stub() {
    private var flow: String? = null
    private var request: DroidGuardResultsRequest? = null
    private val url: String
        get() = DroidGuardPreferences.getNetworkServerUrl(context) ?: throw IllegalStateException("Network URL required")

    override fun init(flow: String?) {
        Log.d(TAG, "init($flow)")
        this.flow = flow
    }

    override fun snapshot(map: Map<Any?, Any?>?): ByteArray {
        Log.d(TAG, "snapshot($map)")
        val paramsMap = mutableMapOf("flow" to flow, "source" to packageName)
        for (key in request?.bundle?.keySet().orEmpty()) {
            request?.bundle?.getString(key)?.let { paramsMap["x-request-$key"] = it }
        }
        val params = paramsMap.map { Uri.encode(it.key) + "=" + Uri.encode(it.value) }.joinToString("&")
        val connection = URL("$url?$params").openConnection() as HttpURLConnection
        val payload = map.orEmpty().map { Uri.encode(it.key as String) + "=" + Uri.encode(it.value as String) }.joinToString("&")
        Log.d(TAG, "POST ${connection.url}: $payload")
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
        connection.requestMethod = "POST"

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Configure the DroidGuard network server URL in microG settings (or via the DroidGuardPreferences setter) before using RemoteHandleImpl
  2. Check DroidGuardPreferences.getNetworkServerUrl(context) for null before constructing/using RemoteHandleImpl and choose a local handle instead
  3. Catch IllegalStateException around handle usage and prompt the user to configure the server URL
  4. If the deployment is local-only, stop instantiating RemoteHandleImpl and use NetworkHandleProxyFactory paths exclusively

Example fix

// before
val handle = RemoteHandleImpl(context, packageName)
handle.init(flow) // throws if no URL configured

// after
val serverUrl = DroidGuardPreferences.getNetworkServerUrl(context)
requireNotNull(serverUrl) { "Configure a DroidGuard network server URL first" }
val handle = RemoteHandleImpl(context, packageName)
handle.init(flow)
Defensive patterns

Strategy: validation

Validate before calling

val serverUrl = DroidGuardPreferences.getNetworkServerUrl(context)
if (serverUrl == null) {
    configureServerUrlOrDefault() // or use a local handle
} else {
    RemoteHandleImpl(context, packageName).init(flow)
}

Try / catch

try {
    remoteHandle.init(flow)
} catch (e: IllegalStateException) {
    promptUserToConfigureDroidGuardServer()
}

Prevention

When it happens

Trigger: Creating a RemoteHandleImpl(context, packageName) and calling init/sendReport/etc. on an install where DroidGuardPreferences.getNetworkServerUrl(context) returns null — i.e. no DroidGuard network server URL has ever been set in preferences.

Common situations: Users who disabled or never configured the DroidGuard network server in microG settings; resetting microG data wipes the configured URL; deployments using only local DroidGuard attempting a remote handle; fork builds missing default server URL configuration.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


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