{"record":{"id":"c011f7914713cce2","repo":"apache/skywalking","slug":"yaml-parsed-to-null-empty-or-malformed-rule-file","errorCode":null,"errorMessage":"YAML parsed to null — empty or malformed rule file: {sourceName}","messagePattern":"YAML parsed to null — empty or malformed rule file: (.+?)","errorType":"http","errorClass":"ApplyException","httpStatus":500,"severity":"error","filePath":"oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/apply/MalFileApplier.java","lineNumber":277,"sourceCode":"                }\n                failures.put(name, t);\n            }\n        }\n        if (failures != null) {\n            throw new RemoveException(failures);\n        }\n    }\n\n    /** Back-compat overload: full-install policy (server-side drop fires). */\n    public void remove(final Set<String> metricNames) {\n        remove(metricNames, StorageManipulationOpt.withSchemaChange());\n    }\n\n    private Rule parse(final String yamlContent, final String sourceName) throws ApplyException {\n        try (StringReader reader = new StringReader(yamlContent)) {\n            final Rule rule = new Yaml().loadAs(reader, Rule.class);\n            if (rule == null) {\n                throw new ApplyException(\"YAML parsed to null — empty or malformed rule file: \"\n                    + sourceName, null, Collections.emptySet());\n            }\n            if (rule.getName() == null || rule.getName().isEmpty()) {\n                rule.setName(sourceName);\n            }\n            // Stamp YAML source anchors from the SAME text we just bound, so a hot-updated rule\n            // gets the same line provenance a disk-loaded one does.\n            RuleSourceLines.assign(rule, yamlContent);\n            // layerDefinitions: are now permitted in runtime MAL rules; they're handled by\n            // the layer registry on the apply path below. The rejection that used to live\n            // here was removed when runtime dynamic layers became a first-class feature.\n            return rule;\n        } catch (final ApplyException e) {\n            throw e;\n        } catch (final Throwable t) {\n            throw new ApplyException(\"YAML parse failure for \" + sourceName, t, Collections.emptySet());\n        }\n    }","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/apply/MalFileApplier.java#L259-L295","documentation":"ApplyException thrown by MalFileApplier.parse when new Yaml().loadAs(reader, Rule.class) returns null — snakeyaml yields null only for an empty document (or a document containing only a null node, e.g. just comments/whitespace). Partial set is empty because nothing was applied. This is distinct from a parse throw (error 133) and from a well-formed-but-incomplete rule (which parses fine and fails later).","triggerScenarios":"Applying an empty or comments-only MAL file, or content reduced to null by templating/CDN pipeline (empty variable substitution producing an empty body). loadAs returns null, the null-check fires, and the apply aborts before name-defaulting or line stamping.","commonSituations":"Uploading a placeholder file created by 'touch rule.yaml' before content was written; CI artifact step emitting an empty file on build failure; Copy operation interrupted, leaving a 0-byte rule file in the store","solutions":["Populate the file with a valid MAL document (top-level name/metricPrefix/metricsRules) and re-apply","Guard uploads: reject empty content client-side before it reaches the runtime-rule API","If a pipeline produced the empty file, fix the artifact step and re-upload","Delete the empty rule entry if it was meant to be a removal — use the uninstall path, not an empty apply"],"exampleFix":"# before (empty file)\n# after\nname: my-bundle\nmetricPrefix: sat\nmetricsRules:\n  - name: throughput\n    exp: \"sum(sat_traffic.total)\"","handlingStrategy":"validation","validationCode":"if (content == null || content.trim().isEmpty()) reject(\"empty rule file\");\nfinal Object probe = new Yaml().load(content); // null for an empty/null document\nif (probe == null) reject(\"document parses to null — no MAL content\");","typeGuard":null,"tryCatchPattern":"catch (ApplyException e) when 'YAML parsed to null': client-side input error — reject the upload, never retry unchanged.","preventionTips":["Reject zero-byte and comments-only files at upload time","Fail CI builds that produce empty rule artifacts","Use the uninstall API for removals instead of empty re-applies"],"tags":["yaml","mal","validation","empty-file"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}