Tencent/matrix · error · GradleException

Need signing apk but $pathOfApkSigner is not exist!

Error message

Need signing apk but $pathOfApkSigner is not exist!

What it means

Thrown by RemoveUnusedResourcesTaskV2.parametersInvalidation when the configured apksigner path is non-empty but the file does not exist. The build fails fast before resource removal, because re-signing later would be impossible.

Solutions

  1. Point apksignerPath at an existing apksigner under $ANDROID_HOME/build-tools/<installed-version>/.
  2. Install the required build-tools version via sdkmanager.
  3. Compute the path from project.buildToolsVersion instead of hardcoding it.
  4. Set useApkSign = false if re-signing is handled elsewhere.

Example fix

// before
apksignerPath = "/Users/me/Library/Android/sdk/build-tools/29.0.2/apksigner" // uninstalled
// after
apksignerPath = "${android.sdkDirectory}/build-tools/${project.buildToolsVersion}/apksigner"
Defensive patterns

Strategy: validation

Validate before calling

def apksigner = file("${android.sdkDirectory}/build-tools/${project.buildToolsVersion}/apksigner")
if (matrix.removeResourceConfig.useApkSign && !apksigner.exists()) {
  throw new GradleException("apksigner missing at ${apksigner}")
}

Prevention

When it happens

Trigger: useApkSign=true with apksignerPath pointing to a missing binary — e.g. stale build-tools version path, typo, or SDK not installed on the machine running the build.

Common situations: SDK upgrades that remove older build-tools directories; different paths on developer machines vs CI; Windows vs Unix path separators copied between configs.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/4dd587238e05a3a7. Report an issue: GitHub.

Appendix: source

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

        } else {
            throw GradleException("the path of Matrix-ApkChecker not found!")
        }

        // Validate path of Zipalign tool
        if (isZipAlignEnabled) {
            if (Util.isNullOrNil(pathOfZipAlign)) {
                throw GradleException("Need zip align apk but the path of zipalign is not specified!")
            } else if (!File(pathOfZipAlign).exists()) {
                throw GradleException("Need zipalign apk but $pathOfZipAlign is not exist!")
            }
        }

        // Validate path of signing
        if (isSigningEnabled) {
            if (Util.isNullOrNil(pathOfApkSigner)) {
                throw GradleException("Need signing apk but the path of apksigner is not specified!")
            } else if (!File(pathOfApkSigner).exists()) {
                throw GradleException("Need signing apk but $pathOfApkSigner is not exist!")
            } else if (AgpCompat.getSigningConfig(variant) == null) {
                throw GradleException("Need signing apk but signingConfig is not specified!")
            }
        }
    }

    private fun calculateResources(
            setOfUnusedResources: Set<String>,
            mapOfDuplicatedResources: Map<String, MutableSet<String>>,
            mapOfResources: MutableMap<String, Int>,
            resultOfResourcesGonnaRemoved: MutableMap<String, Int>,
            resultOfDuplicatesReplacements: MutableMap<String, String>,
            resultOfObfuscatedNames: MutableMap<String, String>
    ) {

        // Prepare unused resources
        val regexpRules = HashSet<String>()
        for (res in rulesOfIgnore) {

View on GitHub (pinned to 3b8293bd65)