Tencent/matrix · error · GradleException

process.errorStream.bufferedReader().readLines().joinTo(Stri…

Error message

process.errorStream.bufferedReader().readLines().joinTo(StringBuilder(), "\n").toString()

What it means

The V2 task runs Matrix-ApkChecker as an external Java process to analyze the APK; if ApkChecker exits non-zero, the task throws a GradleException whose message is the checker process's full stderr. The actual root cause is whatever ApkChecker printed — invalid checker arguments, JVM errors, or analysis failures.

Solutions

  1. Read the stderr text inside the exception — it is ApkChecker's own output; run the same ApkChecker command manually to reproduce.
  2. Verify `pathOfApkChecker` points at a runnable Matrix-ApkChecker jar (`java -jar apkchecker.jar`) and that `java` on PATH is a compatible JDK (8+).
  3. Fix the checker arguments/config the task generates (e.g. remove invalid mapping/resGuard file paths) so the checker exits 0.
  4. Give the checker more memory if it dies with OOM (set JAVA_OPTS or run ApkChecker standalone with -Xmx).

Example fix

// before: missing mapping file passed to checker
mappingFile = "build/outputs/mapping/release/mapping.txt" // not generated (no minify)

// after: only pass mapping when minifyEnabled
mappingFile = (minifyEnabled ? "build/outputs/mapping/release/mapping.txt" : null)
Defensive patterns

Strategy: try-catch

Validate before calling

def exitCode = "java -jar ${pathOfApkChecker} --help".execute().waitFor()
assert exitCode == 0 : 'ApkChecker jar not runnable with current JDK'

Try / catch

try { task.execute() } catch (GradleException e) { logger.error('ApkChecker failed: ' + e.message); throw e }

Prevention

When it happens

Trigger: ApkChecker process launched from `exec` finishes with `exitValue() != 0` — e.g. bad `-config` JSON for the checker, missing checker jar/classes, wrong JDK version, or the checker crashing on the APK.

Common situations: pathOfApkChecker pointing at a jar without a proper Main-Class manifest; ApkChecker run with an unsupported Java version; checker config file referencing resources that don't exist in the APK; out-of-memory in the checker JVM.

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/8ae54db8ad821611. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTaskV2.kt:438

            val parametersOfIgnoredResources = StringBuilder()
            if (configOfIgnoredResources.isNotEmpty()) {
                for (ignore in configOfIgnoredResources) {
                    parametersOfIgnoredResources.append(ignore)
                    parametersOfIgnoredResources.append(',')
                }
                parametersOfIgnoredResources.deleteCharAt(parametersOfIgnoredResources.length - 1)
                parameters.add("--ignoreResources")
                parameters.add(parametersOfIgnoredResources.toString())
            }

            if (findOutDuplicates) {
                parameters.add("-duplicatedFile")
            }

            val process = ProcessBuilder().command(parameters).start()
            ApkUtil.waitForProcessOutput(process)
            if (process.exitValue() != 0) {
                throw GradleException(process.errorStream.bufferedReader().readLines()
                        .joinTo(StringBuilder(), "\n").toString())
            }

            val checkerOutputFile = File(pathOfBuildDir, "apk_checker.json")   // -_-|||
            if (checkerOutputFile.exists()) {
                val jsonArray = Gson().fromJson(checkerOutputFile.readText(), JsonArray::class.java)
                for (i in 0 until jsonArray.size()) {
                    if (jsonArray.get(i).asJsonObject.get("taskType").asInt == 12) {
                        val resList = jsonArray.get(i).asJsonObject.get("unused-resources").asJsonArray
                        for (j in 0 until resList.size()) {
                            resultOfUnused.add(resList.get(j).asString)
                        }
                    }
                    if (jsonArray.get(i).asJsonObject.get("taskType").asInt == 10) {
                        val duplicatedFiles = jsonArray.get(i).asJsonObject.get("files").asJsonArray
                        for (k in 0 until duplicatedFiles.size()) {
                            val obj = duplicatedFiles.get(k).asJsonObject
                            val md5 = obj.get("md5")

View on GitHub (pinned to 3b8293bd65)