{"record":{"id":"d4f529f50555fac0","repo":"Tencent/matrix","slug":"tag-can-not-find-the-tool-nm","errorCode":null,"errorMessage":"TAG + \"---Can not find the tool 'nm'!\"","messagePattern":"TAG \\+ \"---Can not find the tool 'nm'!\"","errorType":"exception","errorClass":"TaskInitException","httpStatus":null,"severity":"error","filePath":"matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnStrippedSoCheckTask.java","lineNumber":83,"sourceCode":"        toolnmPath = params.get(JobConstants.PARAM_TOOL_NM);\n        if (Util.isNullOrNil(toolnmPath)) {\n            throw new TaskInitException(TAG + \"---The path of tool 'nm' is not given!\");\n        } else {\n            Pattern envPattern = Pattern.compile(\"(\\\\$[a-zA-Z_-]+)\");\n            Matcher matcher =  envPattern.matcher(toolnmPath);\n            while (matcher.find()) {\n                if (!Util.isNullOrNil(matcher.group())) {\n                    String env = System.getenv(matcher.group().substring(1));\n                    Log.d(TAG, \"%s -> %s\", matcher.group().substring(1), env);\n                    if (!Util.isNullOrNil(env)) {\n                        toolnmPath = toolnmPath.replace(matcher.group(), env);\n                    }\n                }\n            }\n            Log.i(TAG, \"toolnm pah is %s\", toolnmPath);\n        }\n        if (!FileUtil.isLegalFile(toolnmPath)) {\n            throw new TaskInitException(TAG + \"---Can not find the tool 'nm'!\");\n        }\n        if (!Util.isNullOrNil(inputPath)) {\n            Log.i(TAG, \"inputPath:%s\", inputPath);\n            libDir = new File(inputPath, \"lib\");\n        } else {\n            throw new TaskInitException(TAG + \"---APK-UNZIP-PATH can not be null!\");\n        }\n\n    }\n\n    private boolean isSoStripped(File libFile) throws IOException, InterruptedException {\n        ProcessBuilder processBuilder = new ProcessBuilder(toolnmPath, libFile.getAbsolutePath());\n        Process process = processBuilder.start();\n        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));\n        String line = reader.readLine();\n        boolean result = false;\n        if (!Util.isNullOrNil(line)) {\n            Log.d(TAG, \"%s\", line);","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-apk-canary/src/main/java/com/tencent/matrix/apk/model/task/UnStrippedSoCheckTask.java#L65-L101","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nparams.put(JobConstants.PARAM_TOOL_NM, \"$TOOL_NM\"); // TOOL_NM not exported\n// after\nString nm = System.getenv(\"TOOL_NM\");\nif (nm != null && new File(nm).canExecute()) params.put(JobConstants.PARAM_TOOL_NM, nm);","handlingStrategy":"validation","validationCode":"File nm = new File(resolvedPath);\nif (!(nm.isFile() && nm.canExecute())) {\n    throw new IllegalStateException(\"nm tool missing or not executable: \" + resolvedPath);\n}","typeGuard":"boolean isLegalTool(File f) { return f != null && f.isFile() && f.canExecute(); }","tryCatchPattern":"try {\n    job.run();\n} catch (TaskInitException e) {\n    if (e.getMessage().contains(\"Can not find the tool 'nm'\")) {\n        log.error(\"nm path '{}' invalid; expected executable file\", toolNmPath);\n    } else throw e;\n}","preventionTips":["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."],"tags":["android","apk-canary","file-not-found","tooling"],"backgroundTag":"file-not-found","analyzedSha":"3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7","analyzedAt":"2026-09-08T08:01:39.722Z","contentChangedAt":"2026-09-08T08:01:39.722Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}