{"record":{"id":"90a104466ea2cb34","repo":"alibaba/spring-cloud-alibaba","slug":"support-for-specifying-l-and-lw-with-other-day","errorCode":null,"errorMessage":"Support for specifying 'L' and 'LW' with other days of the month is not implemented","messagePattern":"Support for specifying 'L' and 'LW' with other days of the month is not implemented","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-schedulerx/src/main/java/com/alibaba/cloud/scheduling/schedulerx/util/CronExpression.java","lineNumber":271,"sourceCode":"\t\t\tseconds = new TreeSet<>();\n\t\t\tminutes = new TreeSet<>();\n\t\t\thours = new TreeSet<>();\n\t\t\tdaysOfMonth = new TreeSet<>();\n\t\t\tmonths = new TreeSet<>();\n\t\t\tdaysOfWeek = new TreeSet<>();\n\t\t\tyears = new TreeSet<>();\n\n\t\t\tint exprOn = SECOND;\n\n\t\t\tfinal StringTokenizer exprsTok = new StringTokenizer(expression, \" \\t\",\n\t\t\t\t\tfalse);\n\n\t\t\twhile (exprsTok.hasMoreTokens() && exprOn <= YEAR) {\n\t\t\t\tfinal String expr = exprsTok.nextToken().trim();\n\n\t\t\t\t// throw an exception if L is used with other days of the month\n\t\t\t\tif (exprOn == DAY_OF_MONTH && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(\",\")) {\n\t\t\t\t\tthrow new ParseException(\"Support for specifying 'L' and 'LW' with other days of the month is not implemented\", -1);\n\t\t\t\t}\n\t\t\t\t// throw an exception if L is used with other days of the week\n\t\t\t\tif (exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(\",\")) {\n\t\t\t\t\tthrow new ParseException(\"Support for specifying 'L' with other days of the week is not implemented\", -1);\n\t\t\t\t}\n\t\t\t\tif (exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') + 1) != -1) {\n\t\t\t\t\tthrow new ParseException(\"Support for specifying multiple \\\"nth\\\" days is not implemented.\", -1);\n\t\t\t\t}\n\n\t\t\t\tfinal StringTokenizer vTok = new StringTokenizer(expr, \",\");\n\t\t\t\twhile (vTok.hasMoreTokens()) {\n\t\t\t\t\tfinal String v = vTok.nextToken();\n\t\t\t\t\tstoreExpressionVals(0, v, exprOn);\n\t\t\t\t}\n\n\t\t\t\texprOn++;\n\t\t\t}\n","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/alibaba/spring-cloud-alibaba/blob/115d5901102009492e05d5ec18c3f79cad4077d0/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-schedulerx/src/main/java/com/alibaba/cloud/scheduling/schedulerx/util/CronExpression.java#L253-L289","documentation":"Thrown during CronExpression.buildExpression while parsing the DAY_OF_MONTH field: if the token contains 'L' (last day / last weekday 'LW'), is longer than one char, and also contains a comma (a list of days), the parser refuses it with ParseException. Quartz does not implement combining the 'L'/'LW' modifier with other comma-separated day values.","triggerScenarios":"A cron whose day-of-month field is a list including L or LW, e.g. '0 0 0 15,L * ?' or '0 0 0 1,LW * ?'. The check at CronExpression.java:270-272 matches DAY_OF_MONTH && indexOf('L')!=-1 && length()>1 && contains(',').","commonSituations":"Wanting 'every 15th and the last day of the month' and writing '15,L'; copy-pasting a Unix-style cron (5-field) into the 6/7-field Quartz format and appending a stray list; misunderstanding that L cannot be mixed in a list.","solutions":["Split into two jobs/triggers: one for the fixed days (e.g. '0 0 0 15 * ?') and one for the last day ('0 0 0 L * ?').","If you only need the last day, use 'L' alone; if the last weekday, use 'LW' alone — without a comma list.","Validate the cron with the same CronExpression class at config-load time to catch it before deployment."],"exampleFix":"# before (invalid: L mixed with list)\n0 0 0 15,L * ?\n\n# after (two separate triggers)\n0 0 0 15 * ?   # the 15th\n0 0 0 L * ?    # the last day of month","handlingStrategy":"try-catch","validationCode":"static String validateCron(String cron) throws ParseException {\n    // trial-parse at config/validation time\n    new com.alibaba.cloud.scheduling.schedulerx.util.CronExpression(cron);\n    return cron;\n}","typeGuard":"// reject day-of-month lists containing L/LW before parsing\nstatic boolean isValidDom(String dom) {\n    boolean hasL = dom.indexOf('L') != -1;\n    return !(hasL && dom.length() > 1 && dom.contains(\",\"));\n}","tryCatchPattern":"try {\n    CronExpression expr = new CronExpression(cron);\n} catch (ParseException e) {\n    // e.g. \"Support for specifying 'L' and 'LW' with other days of the month is not implemented\"\n    throw new IllegalArgumentException(\"Invalid cron '\" + cron + \"': \" + e.getMessage(), e);\n}","preventionTips":["Never combine 'L'/'LW' with comma-separated days in one field; use multiple triggers.","Add a startup cron-validation step that trial-parses every configured cron."],"tags":["java","schedulerx","cron","parsing","validation"],"backgroundTag":null,"analyzedSha":"115d5901102009492e05d5ec18c3f79cad4077d0","analyzedAt":"2026-08-14T04:47:13.900Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}