{"record":{"id":"253afedcf40ef2c7","repo":"jeecgboot/JeecgBoot","slug":"unexpected-character-c-after","errorCode":null,"errorMessage":"Unexpected character '${c}' after '/'","messagePattern":"Unexpected character '(.+?)' after '/'","errorType":"validation","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":865,"sourceCode":"            i++;\n            c = s.charAt(i);\n            int v2 = Integer.parseInt(String.valueOf(c));\n            i++;\n            if (i >= s.length()) {\n                checkIncrementRange(v2, type, i);\n                addToSet(val, end, v2, type);\n                return i;\n            }\n            c = s.charAt(i);\n            if (c >= '0' && c <= '9') {\n                ValueSet vs = getValue(v2, s, i);\n                int v3 = vs.value;\n                checkIncrementRange(v3, type, i);\n                addToSet(val, end, v3, type);\n                i = vs.pos;\n                return i;\n            } else {\n                throw new ParseException(\"Unexpected character '\" + c + \"' after '/'\", i);\n            }\n        }\n\n        addToSet(val, end, 0, type);\n        i++;\n        return i;\n    }\n\n    public String getCronExpression() {\n        return cronExpression;\n    }\n\n    public String getExpressionSummary() {\n        StringBuilder buf = new StringBuilder();\n\n        buf.append(\"seconds: \");\n        buf.append(getExpressionSetSummary(seconds));\n        buf.append(\"\\n\");","sourceCodeStart":847,"sourceCodeEnd":883,"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#L847-L883","documentation":"Thrown after the parser has read the first digit following '/' and then encounters a character that is not a digit at the next position. For multi-digit step values this is normal (the parser reads all consecutive digits), but if the character after the first step digit is a letter, special character, or delimiter that is not 0–9, the expression is malformed. Note: if the very first character after '/' is not a digit, Integer.parseInt on the prior line would throw an unchecked NumberFormatException instead — this error specifically fires when the first char IS a digit but a subsequent char is not.","triggerScenarios":"A cron field token like '0/5L' (letter after step), '0/5/' (second slash), '0/5-' (dash after step), or '0/5#' where the parser reads '5' as v2 then sees a non-digit. The token must have a digit immediately after '/', followed by a non-digit that is not whitespace or end-of-string.","commonSituations":"Developer combines step syntax with a modifier incorrectly (e.g., '1/5W'); malformed expression from string concatenation; trailing junk character appended to a valid step value.","solutions":["Remove any non-numeric characters after the step value — the step must be a pure integer.","Separate concerns: use either step ('/') or modifier ('L', 'W', '#') in a single token, not both after the same base value.","Inspect the full field string character-by-character if built dynamically."],"exampleFix":"// before\nString cron = \"0/5W * * * * ?\";  // 'W' after step value\n// after\nString cron = \"0/5 * * * * ?\";  // every 5 seconds","handlingStrategy":"validation","validationCode":"// After '/', ensure only digits follow the step value until end or delimiter\nfor (String field : cronExpr.split(\"\\\\s+\")) {\n    int slashIdx = field.indexOf('/');\n    if (slashIdx >= 0 && slashIdx + 1 < field.length()) {\n        String afterSlash = field.substring(slashIdx + 1);\n        for (char ch : afterSlash.toCharArray()) {\n            if (ch < '0' || ch > '9') {\n                throw new IllegalArgumentException(\"Unexpected character '\" + ch + \"' after '/'\");\n            }\n        }\n    }\n}","typeGuard":"boolean isStepValuePureDigits(String field) {\n    int slashIdx = field.indexOf('/');\n    if (slashIdx < 0 || slashIdx + 1 >= field.length()) return true;\n    String step = field.substring(slashIdx + 1);\n    return step.chars().allMatch(c -> c >= '0' && c <= '9');\n}","tryCatchPattern":"try {\n    CronExpression cron = new CronExpression(expr);\n} catch (ParseException e) {\n    if (e.getMessage().contains(\"Unexpected character\") && e.getMessage().contains(\"after '/'\")) {\n        // remove non-digit characters after the step value\n    }\n    throw e;\n}","preventionTips":["Keep step values after '/' as pure integers with no modifiers.","Do not combine step syntax with 'L', 'W', or '#' in the same token.","Inspect dynamically assembled cron tokens for stray characters."],"tags":["cron","validation","scheduling","xxljob","parse"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}