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

  1. Read the captured stderr in the exception message — it contains apksigner's own diagnosis; fix the underlying signing issue it names.
  2. Verify keystore password, key alias and key password are correct (`keytool -list -keystore ...` or `apksigner sign --ks ...` manually).
  3. Upgrade Android build-tools to a recent version so apksigner matches the APK's minSdk/v1-v4 signature requirements.
  4. 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

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


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)) {
                                break

View on GitHub (pinned to 3b8293bd65)