{"record":{"id":"ae2e3a45583f598b","repo":"apache/hadoop","slug":"bad-rule-definition-bad-lines","errorCode":null,"errorMessage":"Bad rule definition: {bad_lines}","messagePattern":"Bad rule definition: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/HostRestrictingAuthorizationFilter.java","lineNumber":173,"sourceCode":"  private void loadRuleMap(String ruleString) throws IllegalArgumentException {\n    if (ruleString == null || ruleString.equals(\"\")) {\n      LOG.debug(\"Got no rules - will disallow anyone access\");\n    } else {\n      // value: user1,network/bits1,path_glob1|user2,network/bits2,path_glob2...\n      Pattern comma_split = Pattern.compile(\",\");\n      Pattern rule_split = Pattern.compile(\"\\\\||\\n\");\n      // split all rule lines\n      Map<Integer, List<String[]>> splits = rule_split.splitAsStream(ruleString)\n          .map(x -> comma_split.split(x, 3))\n          .collect(Collectors.groupingBy(x -> x.length));\n      // verify all rules have three parts\n      if (!splits.keySet().equals(Collections.singleton(3))) {\n        // instead of re-joining parts, re-materialize lines which do not split\n        // correctly for the exception\n        String bad_lines = rule_split.splitAsStream(ruleString)\n            .filter(x -> comma_split.split(x, 3).length != 3)\n            .collect(Collectors.joining(\"\\n\"));\n        throw new IllegalArgumentException(\"Bad rule definition: \" + bad_lines);\n      }\n      // create a list of Rules\n      int user = 0;\n      int cidr = 1;\n      int path = 2;\n      BiFunction<CopyOnWriteArrayList<Rule>, CopyOnWriteArrayList<Rule>,\n          CopyOnWriteArrayList<Rule>> arrayListMerge = (v1, v2) -> {\n        v1.addAll(v2);\n        return v1;\n      };\n      for (String[] split : splits.get(3)) {\n        LOG.debug(\"Loaded rule: user: {}, network/bits: {} path: {}\",\n            split[user], split[cidr], split[path]);\n        Rule rule = (split[cidr].trim().equals(\"*\") ? new Rule(null,\n            split[path]) : new Rule(new SubnetUtils(split[cidr]).getInfo(),\n            split[path]));\n        // Rule map is {\"user\": [rule1, rule2, ...]}, update the user's array\n        CopyOnWriteArrayList<Rule> arrayListRule =","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/common/HostRestrictingAuthorizationFilter.java#L155-L191","documentation":"HostRestrictingAuthorizationFilter (host-based authorization for WebHDFS/HTTPFS) parses the rule string from the config 'dfs.web.authentication.host.allow.rules' (RESTRICTION_CONFIG under prefix dfs.web.authentication.). Rules are separated by '|' or newlines and each must split on commas into exactly 3 parts (user, network/bits, path). If grouping the splits by length yields anything other than {3}, the filter re-materializes the offending lines and throws IllegalArgumentException('Bad rule definition: ...') during initialization.","triggerScenarios":"Deploying the filter with a rule line containing only 2 comma-separated fields (missing path), 4+ fields where the first two commas are consumed but later validation of structure fails, empty fields, or a stray line from newline mangling — note 'a,b,c,d' splits to length 3 only when the limit-3 split keeps the tail together, but 'a,b' or 'a' yields a non-3 length and trips the check.","commonSituations":"Editing host.allow.rules and dropping the path column; XML config that collapses or breaks newlines so two rules merge; quoting errors when the pipe separator is interpreted by shells or config templating.","solutions":["Rewrite every rule as a strict 'user,cidr,path' triplet, e.g. '*,127.0.0.0/8,/webhdfs/v1', separated by '|' or newlines","Validate the rule string with the same split logic (Pattern \"\\\\||\\n\" then split(',', 3).length == 3) in a pre-deploy check before restarting the service","After fixing, restart the httpfs/webhdfs service so the filter re-initializes, and confirm the 'Loaded rule' debug lines appear"],"exampleFix":"# before (dfs.web.authentication.host.allow.rules)\nalice,10.0.0.0/8          # missing path field -> Bad rule definition\n\n# after\nalice,10.0.0.0/8,/webhdfs/v1|bob,192.168.0.0/16,/webhdfs/v1","handlingStrategy":"validation","validationCode":"static boolean isValidRuleString(String ruleString) {\n  return Pattern.compile(\"\\\\||\\n\").splitAsStream(ruleString)\n      .allMatch(line -> line.split(\",\", 3).length == 3\n          && !line.startsWith(\",\") && !line.endsWith(\",\"));\n}\n\nif (!isValidRuleString(rules)) throw new IllegalArgumentException(\"Bad rule definition: \" + rules);","typeGuard":"static boolean isWellFormedRuleLine(String line) {\n  String[] parts = line.split(\",\", 3);\n  return parts.length == 3\n      && !parts[0].isEmpty() && !parts[1].isEmpty() && !parts[2].isEmpty();\n}","tryCatchPattern":"try {\n  filter.init(filterConfig);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Bad rule definition\")) {\n    failDeployment(\"host.allow.rules malformed: \" + e.getMessage()); // config error, not transient\n  } else throw e;\n}","preventionTips":["Lint dfs.web.authentication.host.allow.rules in CI with the exact 3-comma-field rule before deploy","Use one rule per line (newline separator) in XML to avoid pipe/quoting issues","Smoke-test service startup after any authorization-filter config change"],"tags":["hdfs","webhdfs","httpfs","authorization-filter","config","rule-parsing"],"backgroundTag":"config-parse-error","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}