{"record":{"id":"522b9991a92e515d","repo":"iflytek/astron-agent","slug":"params-error-cron-has-no-future-fire-time","errorCode":"PARAMS_ERROR","errorMessage":"cron has no future fire time","messagePattern":"cron has no future fire time","errorType":"validation","errorClass":"BusinessException","httpStatus":null,"severity":"warning","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowAutomationService.java","lineNumber":167,"sourceCode":"        requireTask(taskId);\n        Page<WorkflowAutomationRun> page = new Page<>(current, pageSize);\n        LambdaQueryWrapper<WorkflowAutomationRun> wrapper = Wrappers.lambdaQuery(WorkflowAutomationRun.class)\n                .eq(WorkflowAutomationRun::getTaskId, taskId)\n                .orderByDesc(WorkflowAutomationRun::getCreateTime);\n        Page<WorkflowAutomationRun> result = runMapper.selectPage(page, wrapper);\n        return toPageData(result);\n    }\n\n    public List<String> preview(String cronExpression, String timezone) {\n        ZoneId zoneId = parseZone(timezone);\n        CronExpression cron = parseCron(cronExpression);\n        ZonedDateTime cursor = ZonedDateTime.now(zoneId);\n        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss z\");\n        java.util.ArrayList<String> result = new java.util.ArrayList<>();\n        for (int i = 0; i < 5; i++) {\n            ZonedDateTime next = cron.next(cursor);\n            if (next == null) {\n                throw new BusinessException(ResponseEnum.PARAMS_ERROR, \"cron has no future fire time\");\n            }\n            result.add(next.format(formatter));\n            cursor = next;\n        }\n        return result;\n    }\n\n    public WorkflowAutomationRun runNow(Long id) {\n        WorkflowAutomationTask task = requireTask(id);\n        return runTask(task, TRIGGER_MANUAL, new Date());\n    }\n\n    public void scanAndRunDueTasks() {\n        Date now = new Date();\n        List<WorkflowAutomationTask> tasks = list(Wrappers.lambdaQuery(WorkflowAutomationTask.class)\n                .eq(WorkflowAutomationTask::getDeleted, false)\n                .eq(WorkflowAutomationTask::getEnabled, true)\n                .le(WorkflowAutomationTask::getNextFireTime, now)","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowAutomationService.java#L149-L185","documentation":"In the cron preview, when the cron expression yields no next fire time after the current instant (cron.next(cursor) returns null), the service throws BusinessException(PARAMS_ERROR, \"cron has no future fire time\"). This happens for expressions whose schedule is entirely in the past or structurally cannot fire again.","triggerScenarios":"Previewing/saving an automation task whose cron expression, evaluated in the configured zoneId from now, has no occurrence in the future — e.g., an explicit date-only schedule that already passed, or a day-of-month/year combination that never matches.","commonSituations":"Users typing crons pinned to a past date (e.g., \"0 0 0 1 1 ? 2024\"); expressions with impossible dates like Feb 30; timezone configuration shifting 'now' past the last occurrence; typos producing a fixed, expired schedule.","solutions":["Correct the cron expression so it recurs or points to a future date; validate it with a cron parser before saving.","Remove the explicit year field or use wildcards so the schedule repeats.","Check the time zone used for preview; an expression valid in another zone may be exhausted in this one."],"exampleFix":"// before\nString cron = \"0 0 9 1 1 ? 2024\"; // already past\nautomationService.preview(flowId, cron);\n// after\nString cron = \"0 0 9 1 1 ? *\"; // recurs every Jan 1\nautomationService.preview(flowId, cron);","handlingStrategy":"validation","validationCode":"function cronHasFutureFire(cron, zone) {\n  const next = cronParser.nextDateFrom(ZonedDateTime.now(zone), cron);\n  return next != null; // false => reject before calling preview\n}","typeGuard":null,"tryCatchPattern":"try { automationService.preview(flowId, cron); } catch (BusinessException e) { if (e.getCode() == PARAMS_ERROR) { showCronEditorError('schedule has no upcoming fire time'); } else throw e; }","preventionTips":["Validate cron expressions with a parser + future-fire check in the UI before saving.","Avoid fixed-year cron expressions; use wildcards for recurring schedules.","Sanity-check impossible dates (Feb 30, day 31 of short months)."],"tags":["cron","scheduling","validation"],"backgroundTag":"invalid-cron-expression","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}