{"record":{"id":"01bb32272c89f9e0","repo":"jeecgboot/JeecgBoot","slug":"invalid-month-value-sub","errorCode":null,"errorMessage":"Invalid Month value: '{sub}'","messagePattern":"Invalid Month value: '(.+?)'","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java","lineNumber":552,"sourceCode":"    }\n\n    protected int storeExpressionVals(int pos, String s, int type)\n            throws ParseException {\n\n        int incr = 0;\n        int i = skipWhiteSpace(pos, s);\n        if (i >= s.length()) {\n            return i;\n        }\n        char c = s.charAt(i);\n        if ((c >= 'A') && (c <= 'Z') && (!s.equals(\"L\")) && (!s.equals(\"LW\")) && (!s.matches(\"^L-[0-9]*[W]?\"))) {\n            String sub = s.substring(i, i + 3);\n            int sval = -1;\n            int eval = -1;\n            if (type == MONTH) {\n                sval = getMonthNumber(sub) + 1;\n                if (sval <= 0) {\n                    throw new ParseException(\"Invalid Month value: '\" + sub + \"'\", i);\n                }\n                if (s.length() > i + 3) {\n                    c = s.charAt(i + 3);\n                    if (c == '-') {\n                        i += 4;\n                        sub = s.substring(i, i + 3);\n                        eval = getMonthNumber(sub) + 1;\n                        if (eval <= 0) {\n                            throw new ParseException(\"Invalid Month value: '\" + sub + \"'\", i);\n                        }\n                    }\n                }\n            } else if (type == DAY_OF_WEEK) {\n                sval = getDayOfWeekNumber(sub);\n                if (sval < 0) {\n                    throw new ParseException(\"Invalid Day-of-Week value: '\"\n                            + sub + \"'\", i);\n                }","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-xxljob/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java#L534-L570","documentation":"Raised in storeExpressionVals when the MONTH field token starts with an uppercase letter (A-Z) but the 3-character substring is not a recognized month abbreviation. getMonthNumber(sub) returns -1, so sval = -1+1 = 0, which is <= 0. The parser only accepts the three-letter abbreviations JAN..DEC in this alphabetic branch; anything else (a typo, a 2-letter code, a non-English abbreviation) fails here.","triggerScenarios":"Cron strings whose month field is an unrecognized alpha token, e.g. '0 0 0 ? JUN,FEB *' is fine but '0 0 0 ? JNE *' (typo), '0 0 0 ? JU *' (truncated), or '0 0 0 ? June *' (full name) trigger it. Also fires when an alpha token in the month position is actually a stray letter from a malformed range like 'JAN-DEC' where the dash parser takes a 3-char slice that is not a month.","commonSituations":"Typing month names from memory and misspelling an abbreviation; using full month names (the parser wants 3 letters only); locale confusion where a developer assumes localized month names are accepted; truncation when an expression is programmatically built by substring and the last token is short.","solutions":["Replace the offending token with a valid 3-letter abbreviation from JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC.","If you prefer numbers, use 1-12 instead of names (1=January).","Check the substring length: the parser reads exactly s.substring(i, i+3), so a 1-2 letter alpha token will produce an invalid slice.","When building ranges like JAN-MAR, ensure both endpoints are valid 3-letter codes."],"exampleFix":"// before - misspelled month abbreviation\nString cron = \"0 0 0 ? JNE ?\";  // 'JNE' invalid -> Invalid Month value: 'JNE'\n\n// after - correct abbreviation (or numeric)\nString cron = \"0 0 0 ? JUN ?\";\n// or\nString cron = \"0 0 0 ? 6 ?\";","handlingStrategy":"validation","validationCode":"private static final java.util.Set<String> MONTHS = java.util.Set.of(\n    \"JAN\",\"FEB\",\"MAR\",\"APR\",\"MAY\",\"JUN\",\"JUL\",\"AUG\",\"SEP\",\"OCT\",\"NOV\",\"DEC\");\n\n// Validate the MONTH field token (single, list, or range) before parsing.\npublic static String validateMonthField(String field) {\n    for (String part : field.split(\",\")) {\n        for (String end : part.split(\"-\")) {\n            String t = end.trim().toUpperCase();\n            if (t.equals(\"*\") || t.equals(\"?\") || t.matches(\"\\\\d+(/\\\\d+)?\")) continue;\n            if (!MONTHS.contains(t)) return \"invalid month token: \" + end;\n        }\n    }\n    return null;\n}","typeGuard":"public static boolean isValidMonthToken(String token) {\n    String t = token == null ? \"\" : token.trim().toUpperCase();\n    return \"*\".equals(t) || \"?\".equals(t)\n        || t.matches(\"\\\\d+(/\\\\d+)?\")\n        || MONTHS.contains(t);\n}","tryCatchPattern":"try {\n    new CronExpression(expr);\n} catch (ParseException e) {\n    if (e.getMessage().startsWith(\"Invalid Month value\")) {\n        // surface a hint about valid 3-letter codes\n        errors.rejectValue(\"monthField\", \"cron.month.invalid\",\n            \"Use JAN..DEC (3 letters) or 1..12. Got: \" + e.getMessage());\n    } else throw e;\n}","preventionTips":["Whitelist month tokens to the 12 valid 3-letter abbreviations at the input layer.","Prefer numeric months (1-12) in generated expressions to avoid abbreviation typos.","In a cron-builder UI, offer month names from a fixed dropdown rather than free text."],"tags":["cron","xxl-job","month-field","validation","parse-error"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}