microg/GmsCore · error · IOException
Server responded with status ${response.status}
Error message
Server responded with status ${response.status} What it means
HttpClient.get throws this IOException when the server responds with any HTTP status other than 200 OK. The decoder expects a 200 body; any redirect, auth failure, rate limit, or server error is surfaced as this exception carrying the actual status code.
Source
Thrown at vending-app/src/main/java/org/microg/vending/billing/core/HttpClient.kt:121
}
}
suspend fun <O> get(
url: String,
headers: Map<String, String> = emptyMap(),
params: Map<String, String> = emptyMap(),
adapter: ProtoAdapter<O>,
cache: Boolean = true
): O {
val response = (if (cache) clientWithCache else client).get(url.asUrl(params)) {
headers {
headers.forEach {
append(it.key, it.value)
}
}
}
if (response.status != HttpStatusCode.OK) throw IOException("Server responded with status ${response.status}")
else return adapter.decode(response.body<ByteArray>())
}
/**
* Post empty body.
*/
suspend fun <I : Message<I, *>, O> post(
url: String,
headers: Map<String, String> = emptyMap(),
params: Map<String, String> = emptyMap(),
adapter: ProtoAdapter<O>,
cache: Boolean = false
): O {
val response = (if (cache) clientWithCache else client).post(url.asUrl(params)) {
setBody(ByteArray(0))
headers {
headers.forEach {
append(it.key, it.value)View on GitHub (pinned to 157c9d86ac)
Solutions
- Inspect response.status in the message and handle 401/403 by refreshing auth credentials/tokens
- Verify the request URL and query params (bav/apiVersion) are correct for the current API version
- Retry with backoff on 429/5xx; check Google service status on widespread 5xx
- Check device date/time correctness, which can break signed auth headers
Example fix
// before
val data = httpClient.get(url, headers)
// after
val data = try {
httpClient.get(url, headers)
} catch (e: IOException) {
if (e.message?.contains("401") == true) refreshAuthAndRetry() else throw e
} Defensive patterns
Strategy: try-catch
Try / catch
try {
httpClient.get(url, headers)
} catch (e: IOException) {
val status = Regex("status (\\d+)").find(e.message ?: "")?.groupValues?.get(1)
when (status) {
"401", "403" -> refreshAuth()
"429", "500", "503" -> retryWithBackoff()
else -> throw e
}
} Prevention
- Refresh auth tokens proactively before they expire
- Keep device clock accurate — clock skew breaks auth headers
- Validate request URLs and API version params
- Implement backoff for 429/5xx responses
When it happens
Trigger: Any GET through HttpClient.get where the Google/Vending endpoint returns 401/403 (bad or expired auth headers), 404 (wrong URL), 429 (rate limited), or 5xx.
Common situations: Expired Google account auth data so HeaderProvider.getDefaultHeaders emits stale tokens; wrong base URL or API version parameter; server-side outage; device clock skew invalidating auth tokens.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- familyResponse is null
- pageContent is null
- Signature invalid
- Network URL required
- Network request failed. message=${e.message}
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/467354b1f431c01e.
Report an issue: GitHub.