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
- Check the configured path — ensure the file exists and is executable.
- Use an absolute path or expand env vars yourself before passing; verify System.getenv resolves them.
- Reinstall/point to the correct NDK or binutils nm (llvm-nm) location.
- 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
- Use absolute paths; expand env vars yourself before passing them.
- Pin the NDK revision and derive the nm path from it programmatically.
- Check the tool exists after CI image updates.
- Run `which nm`/verify llvm-nm in a preflight step.
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
- TAG + "---APK-FILE-PATH '" + inputPath + "' is illegal!"
- TAG + "---APK-UNZIP-PATH '" + inputPath + "' is not exist!"
- ---APK-UNZIP-PATH ' ' is not exist!
- ---APK-UNZIP-PATH ' ' is not exist!
- ---Manifest file ' /AndroidManifest.xml' is not exist!
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)