microg/GmsCore · error · IllegalArgumentException
rolling start interval number missing
Error message
rolling start interval number missing
What it means
TemporaryExposureKeyProto.toKey() requires rolling_start_interval_number (the 10-minute interval at which the key becomes valid). If the received proto lacks this field, the elvis operator throws IllegalArgumentException 'rolling start interval number missing'. Without it the key's validity window cannot be computed, so the conversion fails.
Source
Thrown at play-services-nearby/core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt:249
ExposureDatabase.with(context) { database ->
database.noteAppAction(packageName, "getTemporaryExposureKeyHistory", JSONObject().apply {
put("result", status.statusCode)
put("response_keys_size", response.size)
}.toString())
}
try {
params.callback.onResult(status, response)
} catch (e: Exception) {
Log.w(TAG, "Callback failed", e)
}
}
}
private fun TemporaryExposureKeyProto.toKey(): TemporaryExposureKey = TemporaryExposureKey.TemporaryExposureKeyBuilder()
.setKeyData(key_data?.toByteArray() ?: throw IllegalArgumentException("key data missing"))
.setRollingStartIntervalNumber(rolling_start_interval_number
?: throw IllegalArgumentException("rolling start interval number missing"))
.setRollingPeriod(rolling_period ?: throw IllegalArgumentException("rolling period missing"))
.setTransmissionRiskLevel(transmission_risk_level ?: 0)
.build()
private fun InputStream.copyToFile(outputFile: File) {
outputFile.outputStream().use { output ->
copyTo(output)
output.flush()
}
}
private fun MessageDigest.digest(file: File): ByteArray = file.inputStream().use { input ->
val buf = ByteArray(4096)
var bytes = input.read(buf)
while (bytes != -1) {
update(buf, 0, bytes)
bytes = input.read(buf)
}View on GitHub (pinned to 157c9d86ac)
Solutions
- Reject or repair export entries lacking rolling_start_interval_number before conversion
- Re-download the export and verify checksum/signature
- Default to a sane value only if your use case allows, otherwise skip the entry
- Ensure the diagnosis server publishes spec-compliant exports (all required TEK fields present)
Example fix
// before
.setRollingStartIntervalNumber(rolling_start_interval_number ?: throw IllegalArgumentException("rolling start interval number missing"))
// after
.setRollingStartIntervalNumber(rolling_start_interval_number ?: Int.MIN_VALUE.also { Log.w(TAG, "missing rolling start interval, skipping") }.let { return null }) Defensive patterns
Strategy: validation
Validate before calling
fun TemporaryExposureKeyProto.hasValidRollingStart(): Boolean =
rolling_start_interval_number != null && rolling_start_interval_number > 0 Type guard
fun TemporaryExposureKeyProto?.isConvertibleToKey(): Boolean =
this != null && key_data?.size() ?: 0 > 0 && rolling_start_interval_number != null && rolling_period != null Try / catch
try {
val key = proto.toKey()
} catch (e: IllegalArgumentException) {
if (e.message?.contains("rolling start interval") == true) skipEntry(proto)
else throw e
} Prevention
- Check rolling_start_interval_number presence before conversion
- Validate export files' integrity (signature/checksum) after download
- Keep diagnosis-server exports spec-compliant (all TEK fields set)
- Skip malformed entries with logging rather than aborting batch import
When it happens
Trigger: Parsing an exposure-key export (TEK) proto whose rolling_start_interval_number field is unset; converting diagnosis keys fetched from a server that omitted the field.
Common situations: Malformed or spec-noncompliant diagnosis-server exports; partially written key files; test fixtures missing fields; custom key submission clients that build incomplete protos.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- key data missing
- rolling period missing
- deleteAll was set to true but keys were also provided
- Element in keys cannot be null or empty
- deleteAll=true but keys are provided
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/e737c6b73683e915.
Report an issue: GitHub.