{"record":{"id":"83cc3ce9bdc0f520","repo":"apache/skywalking","slug":"failed-to-load-mal-rules","errorCode":null,"errorMessage":"Failed to load MAL rules","messagePattern":"Failed to load MAL rules","errorType":"exception","errorClass":"ModuleStartException","httpStatus":null,"severity":"critical","filePath":"oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/LogAnalyzerModuleConfig.java","lineNumber":69,"sourceCode":"    private String malFiles;\n\n    private List<Rule> meterConfigs;\n\n    public List<String> lalFiles() {\n        return Splitter.on(\",\").omitEmptyStrings().trimResults().splitToList(Strings.nullToEmpty(getLalFiles()));\n    }\n\n    public List<Rule> malConfigs() throws ModuleStartException {\n        if (nonNull(meterConfigs)) {\n            return meterConfigs;\n        }\n        final List<String> files = Splitter.on(\",\")\n                                           .omitEmptyStrings()\n                                           .splitToList(Strings.nullToEmpty(getMalFiles()));\n        try {\n            meterConfigs = Rules.loadRules(getMalPath(), files);\n        } catch (IOException e) {\n            throw new ModuleStartException(\"Failed to load MAL rules\", e);\n        }\n\n        return meterConfigs;\n    }\n}\n","sourceCodeStart":51,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/LogAnalyzerModuleConfig.java#L51-L75","documentation":"Thrown by the log-analyzer module when loading MAL (meter) rules referenced by log rules: malConfigs() splits the malFiles config on commas and calls Rules.loadRules(malPath, files); any IOException (missing path, unreadable file, YAML structure error surfaced as IO) is wrapped in ModuleStartException and fails provider start. This is the meter-analyzer loader reused for the log-mal-rules catalog, not the LAL loader.","triggerScenarios":"malPath/malFiles under the log-analyzer provider pointing to missing or unreadable files; malformed meter-analyzer YAML (rules not a list, bad indentation) causing a load failure; files listed in malFiles that don't exist under malPath.","commonSituations":"Adding a custom meter rule file for log-derived metrics but forgetting to ship it into the image; typo in the malFiles comma list; copying log-mal-rules config between versions where the rule schema changed.","solutions":["Verify each file in the malFiles list exists under malPath (the IOException cause names the file)","Validate the meter YAML against the shipped log-mal-rules examples (top-level 'rules:' list, correct metric expression syntax)","Remove stale entries from the malFiles comma list","Check the nested IOException cause — it distinguishes missing-file from parse failures"],"exampleFix":"# before\nmalFiles: my-rules.yaml,old-rules.yaml   # old-rules.yaml deleted\n\n# after\nmalFiles: my-rules.yaml","handlingStrategy":"validation","validationCode":"# Pre-start check: every listed file exists under malPath\n# IFS=',' ; for f in $MAL_FILES; do test -f \"$MAL_PATH/$f\" || echo \"missing: $MAL_PATH/$f\"; done","typeGuard":null,"tryCatchPattern":"try {\n    List<Rule> rules = config.malConfigs();\n} catch (ModuleStartException e) {\n    // IOException cause names the file; fix path or YAML, then restart\n}","preventionTips":["Keep the malFiles list in sync with actually shipped files","Validate meter YAML with the same schema as shipped log-mal-rules","Add a packaging check that every configured rule file is present in the dist"],"tags":["mal","log-analyzer","config","startup"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}