Tencent/matrix · error · GradleException
process.errorStream.bufferedReader().readLines().joinTo(Stri…
Error message
process.errorStream.bufferedReader().readLines().joinTo(StringBuilder(), "\n").toString()
What it means
After rebuilding and re-signing the APK, the task runs apksigner as an external process; if apksigner exits with a non-zero exit code, the task throws a GradleException whose message is the entire stderr of that process. This message therefore echoes whatever apksigner reported (e.g. keystore errors, bad passwords, unsupported signature algorithms).
Solutions
- Read the captured stderr in the exception message — it contains apksigner's own diagnosis; fix the underlying signing issue it names.
- Verify keystore password, key alias and key password are correct (`keytool -list -keystore ...` or `apksigner sign --ks ...` manually).
- Upgrade Android build-tools to a recent version so apksigner matches the APK's minSdk/v1-v4 signature requirements.
- Sign the shrunk APK manually with apksigner outside Gradle if automated signing keeps failing.
Example fix
// before (wrong password in signingConfig)
signingConfigs { release { keyPassword "wrongpass" } }
// after
signingConfigs { release { keyPassword System.getenv("KEY_PASSWORD") } } Defensive patterns
Strategy: try-catch
Validate before calling
def proc = [apksigner, 'sign', '--ks', ksFile, '--ks-key-alias', alias, '--ks-pass', 'pass:' + ksPass, '--key-pass', 'pass:' + keyPass, apk].execute() proc.waitFor() assert proc.exitValue() == 0 : proc.errorStream.text
Try / catch
try { removeUnusedResourcesTask.execute() } catch (GradleException e) { logger.error('apksigner failed: ' + e.message); throw e } Prevention
- Test signing manually with apksigner before wiring it into Gradle.
- Store passwords via environment variables/gradle.properties to avoid stale hard-coded values.
- Keep build-tools updated to match APK signature-scheme requirements.
When it happens
Trigger: apksigner invocation in `removeUnusedResources` fails: wrong keystore password, wrong key alias/password, corrupted or incompatible keystore, or apksigner rejecting the unsigned APK — detected via `process.exitValue() != 0`.
Common situations: Stale or wrong `keyPassword`/`keyAlias` in signingConfig; keystore generated with an algorithm the build-tools' apksigner cannot read; min/target SDK requiring v2 signatures with an old build-tools version; quoting issues in the pass arguments.
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
- apksigner returned with status: $ret
- need sign apk but apksigner not found!
- need sign apk but apksigner $apksigner was not exist!
- need sign apk but signingConfig not found!
- process.errorStream.bufferedReader().readLines().joinTo(Stri…
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/4e92efb4e18bde26.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTask.kt:240
}
}
zipOutputStream.close()
Log.i(TAG, "shrink apk size %f KB", (inputFile.length() - outputFile.length()) / 1024.0)
if (needSign) {
Log.i(TAG, "Sign apk...")
val processBuilder = ProcessBuilder()
processBuilder.command(apksigner, "sign", "-v",
"--ks", signingConfig!!.storeFile?.absolutePath,
"--ks-pass", "pass:" + signingConfig.storePassword,
"--key-pass", "pass:" + signingConfig.keyPassword,
"--ks-key-alias", signingConfig.keyAlias,
outputFile.absolutePath)
val process = processBuilder.start()
process.waitFor()
if (process.exitValue() != 0) {
throw GradleException(process.errorStream.bufferedReader().readLines()
.joinTo(StringBuilder(), "\n").toString())
}
}
val backApk = inputFile.parentFile.absolutePath + "/" + inputFile.name.substring(0, inputFile.name.indexOf('.')) + "_back.apk"
inputFile.renameTo(File(backApk))
outputFile.renameTo(File(originalApk))
//modify R.txt to delete the removed resources
if (removeResources.isNotEmpty()) {
val styleableItera = styleableMap.keys.iterator()
while (styleableItera.hasNext()) {
val styleable = styleableItera.next()
val attrs = styleableMap[styleable]
var j = 0
for (i in 0 until (attrs!!.size)) {
j = i
if (!removeResources.containsValue(attrs[i].right)) {
breakView on GitHub (pinned to 3b8293bd65)