Tencent/matrix · error · TaskInitException

TAG + "---Can not find the tool 'nm'!"

Error message

TAG + "---Can not find the tool 'nm'!"

What it means

UnStrippedSoCheckTask.init() throws TaskInitException when the configured 'nm' tool path is non-empty but does not point to a legal, readable executable file (FileUtil.isLegalFile fails). Thrown after env-var expansion of the path.

Solutions

  1. Check the configured path — ensure the file exists and is executable.
  2. Use an absolute path or expand env vars yourself before passing; verify System.getenv resolves them.
  3. Reinstall/point to the correct NDK or binutils nm (llvm-nm) location.
  4. Compare the resolved toolnmPath (the task logs it) with the filesystem.

Example fix

// before
params.put(JobConstants.PARAM_TOOL_NM, "$TOOL_NM"); // TOOL_NM not exported
// after
String nm = System.getenv("TOOL_NM");
if (nm != null && new File(nm).canExecute()) params.put(JobConstants.PARAM_TOOL_NM, nm);
Defensive patterns

Strategy: validation

Validate before calling

File nm = new File(resolvedPath);
if (!(nm.isFile() && nm.canExecute())) {
    throw new IllegalStateException("nm tool missing or not executable: " + resolvedPath);
}

Type guard

boolean isLegalTool(File f) { return f != null && f.isFile() && f.canExecute(); }

Try / catch

try {
    job.run();
} catch (TaskInitException e) {
    if (e.getMessage().contains("Can not find the tool 'nm'")) {
        log.error("nm path '{}' invalid; expected executable file", toolNmPath);
    } else throw e;
}

Prevention

When it happens

Trigger: PARAM_TOOL_NM points to a nonexistent file, a directory, a path containing an unexpanded $ENV_VAR whose value is empty, or a binary that was removed (e.g. path hard-coded to a removed NDK revision).

Common situations: Hard-coding an NDK nm path from a teammate's machine; configuring `nm` as a bare name instead of an absolute path; env var like $ANDROID_NDK_HOME not set in CI so it expands to nothing.

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

Appendix: source

Thrown at matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnStrippedSoCheckTask.java:83

        toolnmPath = params.get(JobConstants.PARAM_TOOL_NM);
        if (Util.isNullOrNil(toolnmPath)) {
            throw new TaskInitException(TAG + "---The path of tool 'nm' is not given!");
        } else {
            Pattern envPattern = Pattern.compile("(\\$[a-zA-Z_-]+)");
            Matcher matcher =  envPattern.matcher(toolnmPath);
            while (matcher.find()) {
                if (!Util.isNullOrNil(matcher.group())) {
                    String env = System.getenv(matcher.group().substring(1));
                    Log.d(TAG, "%s -> %s", matcher.group().substring(1), env);
                    if (!Util.isNullOrNil(env)) {
                        toolnmPath = toolnmPath.replace(matcher.group(), env);
                    }
                }
            }
            Log.i(TAG, "toolnm pah is %s", toolnmPath);
        }
        if (!FileUtil.isLegalFile(toolnmPath)) {
            throw new TaskInitException(TAG + "---Can not find the tool 'nm'!");
        }
        if (!Util.isNullOrNil(inputPath)) {
            Log.i(TAG, "inputPath:%s", inputPath);
            libDir = new File(inputPath, "lib");
        } else {
            throw new TaskInitException(TAG + "---APK-UNZIP-PATH can not be null!");
        }

    }

    private boolean isSoStripped(File libFile) throws IOException, InterruptedException {
        ProcessBuilder processBuilder = new ProcessBuilder(toolnmPath, libFile.getAbsolutePath());
        Process process = processBuilder.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        String line = reader.readLine();
        boolean result = false;
        if (!Util.isNullOrNil(line)) {
            Log.d(TAG, "%s", line);

View on GitHub (pinned to 3b8293bd65)