{"record":{"id":"c4bdcf55d0ec248c","repo":"flowable/flowable-engine","slug":"unexpected-character","errorCode":null,"errorMessage":"Unexpected character: ","messagePattern":"Unexpected character: ","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java","lineNumber":703,"sourceCode":"            }\n            return i;\n        } else if (c >= '0' && c <= '9') {\n            int val = Integer.parseInt(String.valueOf(c));\n            i++;\n            if (i >= s.length()) {\n                addToSet(val, -1, -1, type);\n            } else {\n                c = s.charAt(i);\n                if (c >= '0' && c <= '9') {\n                    ValueSet vs = getValue(val, s, i);\n                    val = vs.value;\n                    i = vs.pos;\n                }\n                i = checkNext(i, s, val, type);\n                return i;\n            }\n        } else {\n            throw new ParseException(\"Unexpected character: \" + c, i);\n        }\n\n        return i;\n    }\n\n    private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException {\n        if (incr > 59 && (type == SECOND || type == MINUTE)) {\n            throw new ParseException(\"Increment > 60 : \" + incr, idxPos);\n        } else if (incr > 23 && (type == HOUR)) {\n            throw new ParseException(\"Increment > 24 : \" + incr, idxPos);\n        } else if (incr > 31 && (type == DAY_OF_MONTH)) {\n            throw new ParseException(\"Increment > 31 : \" + incr, idxPos);\n        } else if (incr > 7 && (type == DAY_OF_WEEK)) {\n            throw new ParseException(\"Increment > 7 : \" + incr, idxPos);\n        } else if (incr > 12 && (type == MONTH)) {\n            throw new ParseException(\"Increment > 12 : \" + incr, idxPos);\n        }\n    }","sourceCodeStart":685,"sourceCodeEnd":721,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/calendar/CronExpression.java#L685-L721","documentation":"CronExpression parses cron strings field by field in storeExpressionVals. When it encounters a character at the current position that cannot start or continue a valid field expression (a digit, '*', '?', '/', or option letter), it throws this ParseException with the offending character and its index. It means the cron expression contains a syntactically invalid character.","triggerScenarios":"Parsing a cron string (new CronExpression(expr) or via CronExpressionFactory) that contains characters like '#', '%', '@', ',' where a value was expected, or a stray letter, e.g. \"0 0 12 * * #\" or whitespace/formatting mistakes, non-ASCII digits, copy-paste artifacts.","commonSituations":"Configuration typos in application.yml / process XML timer definitions; expressions copied from Windows-style or Quartz GUI tools with extra characters; quotes or trailing whitespace characters; localization issues (Unicode digits).","solutions":["Inspect the character and index reported in the message and remove/replace the invalid character","Validate the expression offline against the Quartz cron syntax Flowable uses before deploying","Replace unsupported macros like '@hourly' with the equivalent explicit expression ('0 0 * * * ?')","Ensure the expression has the right number of fields (6-7: sec min hour dom mon dow [year]) so characters fall in expected positions"],"exampleFix":"// before\nnew CronExpression(\"0 0 12 * * #\");\n// after\nnew CronExpression(\"0 0 12 * * ?\");","handlingStrategy":"validation","validationCode":"boolean isValidCron(String expr) {\n    if (expr == null || expr.isBlank()) return false;\n    String allowed = \"0123456789*?,-/LMW#ABCDEFGHIJKLMNOPQRSTUVWXYZabcxyz \";\n    for (char c : expr.toCharArray()) {\n        if (allowed.indexOf(c) < 0 && !Character.isDigit(c)) return false;\n    }\n    int fields = expr.trim().split(\"\\\\s+\").length;\n    return fields == 6 || fields == 7;\n}","typeGuard":null,"tryCatchPattern":"try {\n    CronExpression cron = new CronExpression(cronExpr);\n} catch (ParseException e) {\n    log.error(\"Invalid cron expression '{}' at index {}: {}\", cronExpr, e.getErrorOffset(), e.getMessage());\n    throw new ConfigurationException(\"Bad cron expression\", e);\n}","preventionTips":["Validate cron expressions at configuration load time, not first use","Test expressions with a helper that computes the next fire time","Avoid copying cron strings from dialects with different syntax; use 6-7 field Quartz format","Replace macros like @hourly with explicit Quartz expressions"],"tags":["cron","parse-error","quartz","scheduling"],"backgroundTag":"invalid-argument-format","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}