Cron builder bugs for OH 3 rule triggers

New to OpenHAB and loving it so far.

  • Platform information:
    • Hardware: Raspberry Pi 4
    • OS: OpenHABian 3.1 M3

I have been trying to make a rule that triggers using a cron expression built in the UI - to trigger on the last Monday in May and I am having two problems:

  • The rule doesn’t initialise successfully when I hit Save, and I get the error messages pasted below - seems to be complaining about the format of the cron expression but I used the built in cron expression builder in the UI to create it (it produces the expression 0 4 0 1L 5 ? *)
  • I tagged the rule as a schedule and it does show in the schedule view, but on the last Sunday in May not the last Monday. If I use the cron expression builder recommended in the docs () then I get a different expression: 0 4 0 ? MAY 2L * - this initialises fine when I hit save but appears in the schedule view on the last Tuesday of May.

Can anyone help me with determining (a) if these are bugs or I’m somehow using the cron builder wrong and (b) how I fix the cron expression to make it work as intended?

Thanks in advance!
Jon

I get the following errors in the log when I save the rule with the first expression, created by the built-in cron builder in the UI:


2021-05-05 21:40:03.541 [ERROR] [ore.common.registry.AbstractRegistry] - Cannot inform the listener "org.openhab.core.automation.internal.RuleEngineImpl$2@f4d6ba" about the "UPDATED" event: Value not a number in cron expression '0 4 0 1L 5 ? *' in field 'DayOfMonth': For input string: "1L"
java.lang.IllegalArgumentException: Value not a number in cron expression '0 4 0 1L 5 ? *' in field 'DayOfMonth': For input string: "1L"
	at org.openhab.core.internal.scheduler.CronAdjuster.parseInt(CronAdjuster.java:494) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronAdjuster.parseInt(CronAdjuster.java:484) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronAdjuster.parseRange(CronAdjuster.java:428) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronAdjuster.parseSub(CronAdjuster.java:281) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronAdjuster.parse(CronAdjuster.java:228) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronAdjuster.parseAndAdd(CronAdjuster.java:204) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronAdjuster.<init>(CronAdjuster.java:99) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronSchedulerImpl.schedule(CronSchedulerImpl.java:67) ~[bundleFile:?]
	at org.openhab.core.internal.scheduler.CronSchedulerImpl.schedule(CronSchedulerImpl.java:61) ~[bundleFile:?]
	at org.openhab.core.automation.internal.module.handler.GenericCronTriggerHandler.scheduleJob(GenericCronTriggerHandler.java:60) ~[?:?]
	at org.openhab.core.automation.internal.module.handler.GenericCronTriggerHandler.setCallback(GenericCronTriggerHandler.java:56) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.lambda$0(RuleEngineImpl.java:636) ~[?:?]
	at java.util.ArrayList.forEach(ArrayList.java:1541) ~[?:?]
	at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1085) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.register(RuleEngineImpl.java:633) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.activateRule(RuleEngineImpl.java:850) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.setRule(RuleEngineImpl.java:504) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl.addRule(RuleEngineImpl.java:464) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl$2.added(RuleEngineImpl.java:271) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl$2.updated(RuleEngineImpl.java:282) ~[?:?]
	at org.openhab.core.automation.internal.RuleEngineImpl$2.updated(RuleEngineImpl.java:1) ~[?:?]
	at org.openhab.core.common.registry.AbstractRegistry.notifyListeners(AbstractRegistry.java:387) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractRegistry.notifyListenersAboutUpdatedElement(AbstractRegistry.java:408) [bundleFile:?]
	at org.openhab.core.automation.internal.RuleRegistryImpl.notifyListenersAboutUpdatedElement(RuleRegistryImpl.java:258) [bundleFile:?]
	at org.openhab.core.automation.internal.RuleRegistryImpl.notifyListenersAboutUpdatedElement(RuleRegistryImpl.java:1) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractRegistry.updated(AbstractRegistry.java:314) [bundleFile:?]
	at org.openhab.core.automation.internal.RuleRegistryImpl.updated(RuleRegistryImpl.java:440) [bundleFile:?]
	at org.openhab.core.automation.internal.RuleRegistryImpl.updated(RuleRegistryImpl.java:1) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractRegistry.updated(AbstractRegistry.java:1) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractProvider.notifyListeners(AbstractProvider.java:66) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractProvider.notifyListenersAboutUpdatedElement(AbstractProvider.java:91) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractManagedProvider.update(AbstractManagedProvider.java:118) [bundleFile:?]
	at org.openhab.core.common.registry.AbstractRegistry.update(AbstractRegistry.java:353) [bundleFile:?]
	at org.openhab.core.automation.rest.internal.RuleResource.update(RuleResource.java:238) [bundleFile:?]
	at jdk.internal.reflect.GeneratedMethodAccessor117.invoke(Unknown Source) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:179) [bundleFile:1.0.9]
	at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) [bundleFile:1.0.9]
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201) [bundleFile:1.0.9]
	at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:104) [bundleFile:1.0.9]
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) [bundleFile:1.0.9]
	at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) [bundleFile:1.0.9]
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) [bundleFile:1.0.9]
	at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) [bundleFile:1.0.9]
	at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:267) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:216) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:301) [bundleFile:1.0.9]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPut(AbstractHTTPServlet.java:237) [bundleFile:1.0.9]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:710) [bundleFile:3.1.0]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:276) [bundleFile:1.0.9]
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:852) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:544) [bundleFile:9.4.20.v20190813]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:71) [bundleFile:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:536) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1581) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1307) [bundleFile:9.4.20.v20190813]
	at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:293) [bundleFile:?]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:482) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1549) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1204) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [bundleFile:9.4.20.v20190813]
	at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:80) [bundleFile:?]
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.Server.handle(Server.java:494) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:374) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:268) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:367) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:782) [bundleFile:9.4.20.v20190813]
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:918) [bundleFile:9.4.20.v20190813]
	at java.lang.Thread.run(Thread.java:834) [?:?]

Further testing reveals that the the Schedule view does not match when the rule actually triggers. By setting the trigger to the first Weds of the month (i.e. today) and a few minutes into the future, using a cron expression created using the online tool rather than the UI cron builder, it shows in the design view on the UI as first Thursday of the month, and it shows in the schedule as first Thursday. But it actually triggers the rule correctly on the first Wednesday.

See also

it’s not clear if and when that was fixed, or if some part of creation/applying/displaying escaped the fix

Thanks for that, good to know it’s been noted as a bug. And at least I now know I can trust the online cron expression builder to give the right behaviour even though it means I need to ignore the Schedule view for now.