{"record":{"id":"143f3dc246ea041e","repo":"jeecgboot/JeecgBoot","slug":"illegal-month-number-monthnum","errorCode":null,"errorMessage":"Illegal month number: ${monthNum}","messagePattern":"Illegal month number: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","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":1642,"sourceCode":"                return 30;\n            case 5:\n                return 31;\n            case 6:\n                return 30;\n            case 7:\n                return 31;\n            case 8:\n                return 31;\n            case 9:\n                return 30;\n            case 10:\n                return 31;\n            case 11:\n                return 30;\n            case 12:\n                return 31;\n            default:\n                throw new IllegalArgumentException(\"Illegal month number: \"\n                        + monthNum);\n        }\n    }\n\n\n    private Optional<Integer> findSmallestDay(int day, int mon, int year, TreeSet<Integer> set) {\n        if (set.isEmpty()) {\n            return Optional.empty();\n        }\n\n        final int lastDay = getLastDayOfMonth(mon, year);\n        // For \"L\", \"L-1\", etc.\n        final int smallestDay = Optional.ofNullable(set.ceiling(LAST_DAY_OFFSET_END - (lastDay - day)))\n                .map(d -> d - LAST_DAY_OFFSET_START + 1)\n                .orElse(Integer.MAX_VALUE);\n\n        // For \"1\", \"2\", etc.\n        SortedSet<Integer> st = set.subSet(day, LAST_DAY_OFFSET_START);","sourceCodeStart":1624,"sourceCodeEnd":1660,"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#L1624-L1660","documentation":"Thrown as IllegalArgumentException from getLastDayOfMonth when the monthNum parameter does not match any of the switch cases 1–12. This is a defensive guard in a method that returns the number of days in a given month (accounting for February leap years via a separate check). Under normal operation the monthNum always comes from validated cron data and is 1–12; this error indicates corrupted state or an unexpected code path feeding an invalid month.","triggerScenarios":"Internal call to getLastDayOfMonth with a value outside 1–12 — e.g., 0, 13, or a negative number. This would require the cron expression's month field to have bypassed the addToSet range check (error 311) or for month data to be corrupted in memory.","commonSituations":"Extremely rare in practice; could occur if the CronExpression object is modified reflectively, if a subclass overrides month handling, or if there is a concurrency issue where the TreeSet is modified during iteration. Most likely indicates a bug in custom code that calls getLastDayOfMonth directly.","solutions":["If calling getLastDayOfMonth directly from custom code, validate monthNum is 1–12 before invoking.","Ensure the cron expression's month field passed validation — check for error 311 in logs.","Verify thread safety: CronExpression objects should not be shared across threads without synchronization if fields can change."],"exampleFix":"// before\nint days = cronExpression.getLastDayOfMonth(0, 2024);  // 0 is invalid\n// after\nint days = cronExpression.getLastDayOfMonth(1, 2024);  // January","handlingStrategy":"try-catch","validationCode":"if (monthNum < 1 || monthNum > 12) {\n    throw new IllegalArgumentException(\"Month must be 1-12, got: \" + monthNum);\n}\nint days = cronExpression.getLastDayOfMonth(monthNum, year);","typeGuard":"boolean isValidMonthNum(int monthNum) {\n    return monthNum >= 1 && monthNum <= 12;\n}","tryCatchPattern":"try {\n    int days = cronExpression.getLastDayOfMonth(mon, year);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Illegal month number\")) {\n        // log and handle corrupted month state; reset CronExpression\n    }\n    throw e;\n}","preventionTips":["Validate month values are 1–12 before calling getLastDayOfMonth.","Ensure CronExpression objects are not shared unsafely across threads.","Avoid reflective modification of internal cron field sets."],"tags":["cron","scheduling","xxljob","runtime","illegal-argument","defensive"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}