{"record":{"id":"8892b6de919fd412","repo":"xuxueli/xxl-job","slug":"can-only-be-specified-for-day-of-month-or-da","errorCode":null,"errorMessage":"'?' can only be specified for Day-of-Month -OR- Day-of-Week.","messagePattern":"'\\?' can only be specified for Day-of-Month -OR- Day-of-Week\\.","errorType":"validation","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java","lineNumber":626,"sourceCode":"            addToSet(sval, eval, incr, type);\n            return (i + 3);\n        }\n\n        if (c == '?') {\n            i++;\n            if ((i + 1) < s.length()\n                    && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\\t')) {\n                throw new ParseException(\"Illegal character after '?': \"\n                        + s.charAt(i), i);\n            }\n            if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {\n                throw new ParseException(\n                        \"'?' can only be specified for Day-of-Month or Day-of-Week.\",\n                        i);\n            }\n            if (type == DAY_OF_WEEK) {\n                if (!daysOfMonth.isEmpty() && daysOfMonth.last() == NO_SPEC_INT) {\n                    throw new ParseException(\n                            \"'?' can only be specified for Day-of-Month -OR- Day-of-Week.\",\n                            i);\n                }\n            }\n\n            addToSet(NO_SPEC_INT, -1, 0, type);\n            return i;\n        }\n\n        if (c == '*' || c == '/') {\n            if (c == '*' && (i + 1) >= s.length()) {\n                addToSet(ALL_SPEC_INT, -1, incr, type);\n                return i + 1;\n            } else if (c == '/'\n                    && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s\n                    .charAt(i + 1) == '\\t')) {\n                throw new ParseException(\"'/' must be followed by an integer.\", i);\n            } else if (c == '*') {","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/xuxueli/xxl-job/blob/e74c784f68f81fa89cb350913ef15794865d7b12/xxl-job-admin/src/main/java/com/xxl/job/admin/business/scheduler/cron/CronExpression.java#L608-L644","documentation":"This error is thrown by the cron expression parser when the '?' (no-value) marker appears in the Day-of-Week field while the Day-of-Month field has already been set to '?' (NO_SPEC_INT). Quartz-style cron requires that exactly one of the two day fields (day-of-month or day-of-week) carries '?' to signal 'no specific value' while the other specifies actual days; both being '?' is ambiguous and illegal.","triggerScenarios":"A cron expression like '0 0 0 ? * ?' where both the day-of-month and day-of-week fields contain '?'. The parser processes fields left-to-right; when it reaches the day-of-week field and sees '?' after day-of-month was already stored as NO_SPEC_INT (98), it throws.","commonSituations":"Copy-pasting a template cron string and replacing the day-of-month value with '?' without updating day-of-week, or auto-generating cron strings from a UI that defaults both day fields to '?'.","solutions":["Change one of the two '?' day-field values to an actual day specifier (e.g., '*' or a number/range) so only one day field uses '?'.","If you mean 'every day', use '0 0 0 * * ?' — day-of-month gets '*' and day-of-week gets '?'.","If you mean a specific weekday, use '0 0 0 ? * FRI' — day-of-month gets '?' and day-of-week gets the weekday."],"exampleFix":"// before\n\"0 0 0 ? * ?\"\n// after\n\"0 0 0 * * ?\"","handlingStrategy":"validation","validationCode":"// Ensure exactly one day field is '?' and the other has a value\nString[] parts = cron.trim().split(\"\\\\s+\");\nString dom = parts.length > 3 ? parts[3] : \"\";\nString dow = parts.length > 5 ? parts[5] : \"\";\nif (dom.equals(\"?\") && dow.equals(\"?\")) {\n    throw new IllegalArgumentException(\"Both day-of-month and day-of-week are '?'; one must have a value.\");\n}","typeGuard":"// Narrow a field token to 'has value or single ?'\nboolean isValidDayFieldPair(String dom, String dow) {\n    boolean domIsQ = \"?\".equals(dom);\n    boolean dowIsQ = \"?\".equals(dow);\n    return domIsQ ^ dowIsQ; // exactly one is '?'","tryCatchPattern":"try {\n    new CronExpression(cron);\n} catch (ParseException e) {\n    if (e.getMessage().contains(\"'?' can only be specified\")) {\n        // fix the day-field conflict and retry\n    }\n}","preventionTips":["Always pair day-of-month '?' with a real day-of-week value, and vice versa.","Use a cron expression builder library that enforces the mutual-exclusivity constraint at construction time.","Add a unit test that asserts known-good cron strings parse without error."],"tags":["cron","validation","quartz","scheduling"],"backgroundTag":null,"analyzedSha":"e74c784f68f81fa89cb350913ef15794865d7b12","analyzedAt":"2026-08-14T04:22:43.715Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}