microg/GmsCore · error · StandardIntegrityException
IntegrityErrorCode.NONCE_TOO_SHORT
IntegrityErrorCode.NONCE_TOO_SHORT
Error message
Nonce too short.
What it means
The nonce byte array supplied to requestIntegrityToken is shorter than the 16-byte minimum enforced by the service. Nonces must be long enough to be unguessable; anything under 16 bytes is rejected with IntegrityErrorCode.NONCE_TOO_SHORT.
Source
Thrown at vending-app/src/main/kotlin/com/google/android/finsky/integrityservice/IntegrityService.kt:122
runCatching {
val packageName = request.getString(KEY_PACKAGE_NAME)
if (packageName == null) {
throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, "Null packageName.")
}
integrityData = callerAppToIntegrityData(context, packageName)
if (integrityData?.allowed != true) {
throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, "Not allowed to request integrity token.")
}
val playIntegrityEnabled = VendingPreferences.isDeviceAttestationEnabled(context)
if (!playIntegrityEnabled) {
throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, "API is disabled.")
}
val nonceArr = request.getByteArray(KEY_NONCE)
if (nonceArr == null) {
throw StandardIntegrityException(IntegrityErrorCode.INTERNAL_ERROR, "Nonce missing.")
}
if (nonceArr.size < 16) {
throw StandardIntegrityException(IntegrityErrorCode.NONCE_TOO_SHORT, "Nonce too short.")
}
if (nonceArr.size >= 500) {
throw StandardIntegrityException(IntegrityErrorCode.NONCE_TOO_LONG, "Nonce too long.")
}
val cloudProjectNumber = request.getLong(KEY_CLOUD_PROJECT, 0L)
val playCoreVersion = request.getPlayCoreVersion()
Log.d(TAG, "requestIntegrityToken(packageName: $packageName, nonce: ${nonceArr.encodeBase64(false)}, cloudProjectNumber: $cloudProjectNumber, playCoreVersion: $playCoreVersion)")
val packageInfo = context.packageManager.getPackageInfoCompat(packageName, SIGNING_FLAGS)
val timestamp = makeTimestamp(System.currentTimeMillis())
val versionCode = packageInfo.versionCode
val integrityParams = IntegrityParams(
packageName = PackageNameWrapper(packageName),
versionCode = VersionCodeWrapper(versionCode),
nonce = nonceArr.encodeBase64(noPadding = false, noWrap = true, urlSafe = true),
certificateSha256Digests = packageInfo.signaturesCompat.map {
it.toByteArray().sha256().encodeBase64(noPadding = true, noWrap = true, urlSafe = true)View on GitHub (pinned to 157c9d86ac)
Solutions
- Generate the nonce with a cryptographic source of at least 16 bytes, e.g. ByteArray(16).also { SecureRandom().nextBytes(it) } or a full SHA-256 digest (32 bytes).
- Check nonceArr.size >= 16 at the call site before sending the request.
- If using a hash, do not truncate it — keep the full digest bytes.
- Ensure any Base64 decode of the nonce is correct so it yields the expected length.
Example fix
// before
val nonce = System.currentTimeMillis().toString().toByteArray() // ~13 bytes
// after
val nonce = ByteArray(32).also { SecureRandom().nextBytes(it) } // or MessageDigest SHA-256 of request data Defensive patterns
Strategy: validation
Validate before calling
fun isNonceTooShort(nonce: ByteArray) = nonce.size < 16
if (isNonceTooShort(nonce)) throw IllegalArgumentException("Nonce must be >= 16 bytes") Type guard
fun ByteArray?.isNonceValid(): Boolean = this != null && size in 16..499
Try / catch
try {
integrityManager.requestIntegrityToken(request)
} catch (e: StandardIntegrityException) {
if (e.errorCode == IntegrityErrorCode.NONCE_TOO_SHORT) {
regenerateNonceAndRetry()
} else throw e
} Prevention
- Generate nonces with SecureRandom or a full SHA-256 digest, never short IDs
- Assert nonce length (16..499) in a shared helper before every call
- Never truncate hashes used as nonces
When it happens
Trigger: Calling requestIntegrityToken with a KEY_NONCE byte array whose size < 16, e.g. a short string converted to bytes or a truncated hash.
Common situations: Using short custom strings like a timestamp or user ID as the nonce; truncating a hash/digest to a few bytes; encoding issues that shrink the payload (e.g. wrong Base64 decode); generating a nonce from a 8-byte value.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- IntegrityErrorCode.NONCE_TOO_LONG
- deleteAll was set to true but keys were also provided
- Element in keys cannot be null or empty
- deleteAll=true but keys are provided
- retrieveAll was set to true but other constraint(s) was also
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/313ac3f4e90c6736.
Report an issue: GitHub.