apache/dolphinscheduler · error · ServiceException

10140

10140

Error message

parse cron to cron expression error

What it means

During updateSchedule, the scheduleExpression JSON string is deserialized into a ScheduleParam; when the string is non-empty but does not parse (or yields an empty object), JSONUtils.parseObject returns null and PARSE_TO_CRON_EXPRESSION_ERROR is thrown. It indicates the scheduleExpression payload is not the expected JSON shape.

Source

Thrown at dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/SchedulerServiceImpl.java:552

                                    FailureStrategy failureStrategy, Priority workflowInstancePriority,
                                    String workerGroup, String tenantCode, long environmentCode) {
        if (schedule.getReleaseState() == ReleaseState.ONLINE) {
            log.warn("Schedule can not be updated due to schedule is {}, scheduleId:{}.",
                    ReleaseState.ONLINE.getDescp(), schedule.getId());
            throw new ServiceException(Status.SCHEDULE_CRON_ONLINE_FORBID_UPDATE);
        }

        Date now = new Date();

        tenantExistValidator.validate(tenantCode);
        schedule.setTenantCode(tenantCode);

        // updateWorkflowInstance param
        if (!StringUtils.isEmpty(scheduleExpression)) {
            ScheduleParam scheduleParam = JSONUtils.parseObject(scheduleExpression, ScheduleParam.class);
            if (scheduleParam == null) {
                log.warn("Parameter scheduleExpression is invalid, so parse cron error.");
                throw new ServiceException(Status.PARSE_TO_CRON_EXPRESSION_ERROR);
            }
            if (DateUtils.differSec(scheduleParam.getStartTime(), scheduleParam.getEndTime()) == 0) {
                log.warn("The start time must not be the same as the end or time can not be null.");
                throw new ServiceException(Status.SCHEDULE_START_TIME_END_TIME_SAME);
            }
            if (scheduleParam.getStartTime().getTime() > scheduleParam.getEndTime().getTime()) {
                log.warn("The start time must smaller than end time");
                throw new ServiceException(Status.START_TIME_BIGGER_THAN_END_TIME_ERROR);
            }

            schedule.setStartTime(scheduleParam.getStartTime());
            schedule.setEndTime(scheduleParam.getEndTime());
            if (!CronUtils.isValidExpression(scheduleParam.getCrontab())) {
                log.error("Schedule crontab verify failure, crontab:{}.", scheduleParam.getCrontab());
                throw new ServiceException(Status.SCHEDULE_CRON_CHECK_FAILED, scheduleParam.getCrontab());
            }
            schedule.setCrontab(scheduleParam.getCrontab());
            validateMissedFirePolicy(scheduleParam);

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Send scheduleExpression as a valid ScheduleParam JSON object with startTime, endTime, and crontab fields.
  2. Validate the JSON with a parser/linter before calling the API.
  3. Check shell quoting and escaping when building the request from scripts.
  4. Omit the parameter entirely (empty string) if you do not want to change the schedule expression, rather than sending garbage.

Example fix

// before
String scheduleExpression = "0 0 12 * * ?";              // raw cron, not JSON

// after
String scheduleExpression = "{\"startTime\":1690000000000,\"endTime\":1890000000000,\"crontab\":\"0 0 12 * * ?\"}";
Defensive patterns

Strategy: validation

Validate before calling

JSONUtils.parseObject(scheduleExpression, ScheduleParam.class); // assert non-null before calling
if (JSONUtils.parseObject(scheduleExpression, ScheduleParam.class) == null) {
    throw new IllegalArgumentException("scheduleExpression is not valid ScheduleParam JSON");
}

Try / catch

try {
    schedulerService.updateSchedule(loginUser, projectCode, id, scheduleExpression, ...);
} catch (ServiceException e) {
    if (e.getCode() == Status.PARSE_TO_CRON_EXPRESSION_ERROR.getCode()) {
        // fix scheduleExpression JSON shape: {startTime, endTime, crontab}
    }
}

Prevention

When it happens

Trigger: Passing a scheduleExpression that is non-empty but invalid JSON (truncated, quoted wrongly), or valid JSON missing required fields so the resulting ScheduleParam is null/unusable.

Common situations: API clients sending the crontab string directly instead of a JSON object like {"startTime":..., "endTime":..., "crontab":"..."}; shell scripts with broken quoting; encoding issues mangling the JSON.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/ba38adf00a1d4579. Report an issue: GitHub.