{"record":{"id":"edf70ebb1589f83d","repo":"languagetool-org/languagetool","slug":"please-set-min-and-max-attributes-on-the-first-tok","errorCode":null,"errorMessage":"Please set min and max attributes on the first token in the AND group.\\n You attempted to set these attributes on the token no. + (andGroupCounter + 1) + .\\n Line: + pLocator.getLineNumber() + , column: + pLocator.getColumnNumber() + .","messagePattern":"Please set min and max attributes on the first token in the AND group\\.\\\\n You attempted to set these attributes on the token no\\. \\+ \\(andGroupCounter \\+ 1\\) \\+ \\.\\\\n Line: \\+ pLocator\\.getLineNumber\\(\\) \\+ , column: \\+ pLocator\\.getColumnNumber\\(\\) \\+ \\.","errorType":"validation","errorClass":"SAXException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/patterns/XMLRuleHandler.java","lineNumber":631,"sourceCode":"    if (maxOccurrence != 1) {\n      patternToken.setMaxOccurrence(maxOccurrence);\n      maxOccurrence = 1;\n    }\n    if (posToken != null) {\n      patternToken.setPosToken(obtainPosToken(posToken, posRegExp, posNegation));\n      posToken = null;\n    }\n    if (chunkTag != null) {\n      patternToken.setChunkTag(chunkTag);\n      chunkTag = null;\n    }\n    if (tokenReference != null) {\n      patternToken.setMatch(tokenReference);\n    }\n    if (inAndGroup && andGroupCounter > 0) {\n      patternTokens.get(patternTokens.size() - 1).setAndGroupElement(patternToken);\n        if (minOccurrence !=1 || maxOccurrence !=1) {\n            throw new SAXException(\"Please set min and max attributes on the \" +\n                    \"first token in the AND group.\\n You attempted to set these \" +\n                    \"attributes on the token no. \" + (andGroupCounter + 1) + \".\" + \"\\n Line: \"\n                    + pLocator.getLineNumber() + \", column: \"\n                    + pLocator.getColumnNumber() + \".\");\n        }\n    } else if (inOrGroup && orGroupCounter > 0) {\n      patternTokens.get(patternTokens.size() - 1).setOrGroupElement(patternToken);\n    } else {\n      if (minOccurrence < 1) {\n        patternTokens.add(patternToken);\n      }\n      for (int i = 1; i <= minOccurrence; i ++) {\n        patternTokens.add(patternToken);\n      }\n      minOccurrence = 1;\n    }\n    if (inAndGroup) {\n      andGroupCounter++;","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/patterns/XMLRuleHandler.java#L613-L649","documentation":"XMLRuleHandler throws this SAXException when min/max occurrence attributes are set on a token that is not the first element of an AND group. In an AND group, occurrence constraints are only meaningful on the first token, because the group is matched in parallel; setting them on later group members (andGroupCounter > 0) is invalid. The message names which group token and the XML line/column.","triggerScenarios":"Parsing an <and> group whose second-or-later token has min=\"..\"/max=\"..\" set while inAndGroup && andGroupCounter > 0, e.g. <token min=\"2\"/> inside an AND group after the first token.","commonSituations":"Authors trying to express 'repeat this member of the AND group' — repetition must instead be modeled outside the group; refactoring a plain token sequence into an AND group while keeping per-token min/max.","solutions":["Remove min/max from non-first tokens in the AND group; set them only on the first token","Restructure the rule (split into multiple patterns or use a different grouping) if you need per-element repetition","Validate the rule with LanguageTool's rule tests after editing"],"exampleFix":"// before\n<and><token>a</token><token min=\"2\" max=\"3\">b</token></and>\n// after\n<and><token min=\"2\" max=\"3\">a</token><token>b</token></and>","handlingStrategy":"validation","validationCode":"// Check AND-group members after the first for min/max attributes\nfor (int i = 1; i < andGroupTokens.size(); i++) {\n  Element t = andGroupTokens.get(i);\n  if (t.hasAttribute(\"min\") || t.hasAttribute(\"max\")) {\n    throw new IllegalArgumentException(\"min/max only allowed on first token of AND group\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  loader.getRules(is, filename);\n} catch (SAXException e) {\n  if (e.getMessage().contains(\"first token in the AND group\")) {\n    log.error(\"Move min/max to the first AND-group token\", e);\n  } else throw e;\n}","preventionTips":["Only set min/max on the first token of an AND group","Model member-level repetition outside AND groups","Run rule tests after refactoring tokens into AND groups"],"tags":["languagetool","xml-rules","validation","and-group"],"backgroundTag":"invalid-argument-value","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}