Quartz Scheduler Extension 1.0.0.53

Quartz Scheduler Extension 1.0.0.53
The link is there with these

  • Overview - Status (failed)
  • Jobs - NO UI just text
  • Listeners - NO UI just text
  • Storage - error message

OS: Arch Linux - latest
Java Version: 25.0.4.1
Jetty Version: 12.1.12
Lucee Version: 7.1.0.204

What context should extensions be running in? I installed the Quartz Scheduler and started getting error logged by my Application.cfc.

/org/lucee/extension/quartz/QuartzGateway.cfc

Should this be hitting my App’s Application.cfc?

I created a whitelist to allow the QuartzGateway to run. Now I am getting errors. AI produced this.

The error at line 64 of overview.cfm is a symptom of two chained failures:

Immediate Error:
overview.cfm:64
attempts to evaluate . However, hasStorage is only set if
Action.cfc:overview()
succeeds. Because an exception occurred during overview(), hasStorage was never initialized, causing Lucee to throw:
text

variable [HASSTORAGE] doesn’t exist
Root Cause (The Underlying Exception): In application.log and gateway.log, overview() failed because sendGatewayMessage(“quartz-task”, …) threw:
text

Component [org.lucee.extension.quartz.QuartzGateway] has no accessible Member with name [CONFIGFILE]
In Lucee’s Event Gateway architecture (CFCGateway.java / GatewayEngineImpl.java), Lucee does not maintain a single persistent CFC instance across calls. Every invocation (init, start, getState, sendMessage) creates a new QuartzGateway.cfc instance. Because variables.configFile was only set inside init(), subsequent calls to start() and sendMessage() on new instances find variables.configFile undefined.
Deep-Dive Analysis

  1. The Immediate Failure: overview.cfm:64
    In
    QuartzStore/Action.cfc
    :

cfm

public function overview(struct lang, struct app, struct req) {
try {
variables.state = GatewayState(variables.gatewayName);
variables.storage = sendGatewayMessage(variables.gatewayName, {
“action”: “store”
,“type”: “raw”
});
variables.storageLoaded = deserializeJSON(variables.storage);
variables.hasStorage = structCount(storageLoaded) > 0;
}
catch(cfcatch) {
handleException(lang, app, req, cfcatch);
}
}
When sendGatewayMessage fails:

variables.hasStorage is never set.
handleException logs the error and stores the exception in session[“expectionQuartzStore”].
The controller proceeds to render
overview.cfm
:
cfm

64:
65:

Modify your Storage


…
68: <cfif structKeyExists(session,exceptionKey)>
69:

…
100:
Because line 64 references hasStorage directly without a default or structKeyExists, it fails before it can even evaluate the or reach the block.

  1. The Underlying Root Cause: QuartzGateway.cfc
    From D:\Jetty-Bases\Jetty-Base-12\lucee-server\context\logs\application.log:

text

“ERROR”,“qtp1660794022-190”,“09/08/2026”,“23:19:49”,“https://local.caminha.me:443”,“webadmin7.1.0.204”,
“Component [org.lucee.extension.quartz.QuartzGateway] has no accessible Member with name [CONFIGFILE]
at org.lucee.extension.quartz.quartzgateway_cfc$cf.udfCall(/org/lucee/extension/quartz/QuartzGateway.cfc:124)
at lucee.runtime.functions.gateway.SendGatewayMessage.call(SendGatewayMessage.java:36)
at quartzstore.action_cfc$cf.udfCall(/lucee_plugin_directory/QuartzStore/Action.cfc:55)”
And in gateway.log:

text

“ERROR”,“EventGateway-quartz-task”,“09/08/2026”,“23:19:37”,“https://local.caminha.me:443”,“Gateway:quartz-task”,
“Component [org.lucee.extension.quartz.QuartzGateway] has no accessible Member with name [CONFIGFILE]”
Looking at
QuartzGateway.cfc
:

cfm

public void function init(string id, struct config, component listener) {
var path = server.system.environment.QUARTZ_CONFIGFILE ?: “”;
if (isEmpty(path)) {
path = config.custom.configFile ?: “{lucee-server}/quartz/config.json”;
path = expandPath(path);
}
variables.configFile = path;
…
}
public void function start() {
variables.instance = new Quartz(variables.configFile); // ← Fails here if init() was on another instance
variables.instance.start();
}
public string function sendMessage(struct data) {
if (!isNull(variables.instance))
return variables.instance.sendMessageInstance(data);
else {
return Quartz::sendMessageStatic(variables.configFile, data); // ← Fails here at line 124
}
}
Why variables.configFile does not exist:
In Lucee’s event gateway implementation (lucee.runtime.gateway.GatewayEngineImpl):

engine.call and engine.callOneWay call getCFC(pc, uri), which instantiates a new instance of QuartzGateway.cfc for each operation in a temporary PageContext.
When the gateway is initialized, init(…) is called on Instance #1, setting variables.configFile on Instance #1.
When the gateway starts (EventGateway-quartz-task), start() is invoked on Instance #2. Instance #2 has an empty variables scope, so variables.configFile is undefined. start() throws an error and the gateway remains stopped.
When the admin page runs sendGatewayMessage, Instance #3 is created. Because the gateway is stopped, sendMessage executes Quartz::sendMessageStatic(variables.configFile, data). Again, Instance #3 has an empty variables scope, throwing Component [org.lucee.extension.quartz.QuartzGateway] has no accessible Member with name [CONFIGFILE].
Recommended Remediation Plan
To make the Quartz extension robust and prevent these failures:

  1. Fix
    QuartzGateway.cfc
    Persist state in static scope: In Lucee, static variables persist across CFC instantiations. Storing static.configFile and static.instance ensures that start(), stop(), getState(), and sendMessage() share the configuration and the running Quartz scheduler instance.
    Self-Healing getConfigFile(): Add a fallback helper that returns static.configFile if available, or resolves server.system.environment.QUARTZ_CONFIGFILE ?: expandPath(“{lucee-server}/quartz/config.json”) and creates the default directory and config file if it does not already exist.
    cfm

component {
static {
static.DEFAULT_CONFIG = ‘…’;
static.instance = nullValue();
static.configFile = “”;
static.config = {};
static.id = “”;
}
private string function getConfigFile(struct config = {}) {
if (len(static.configFile) && fileExists(static.configFile)) {
return static.configFile;
}
var path = server.system.environment.QUARTZ_CONFIGFILE ?: “”;
if (isEmpty(path)) {
path = arguments.config.custom.configFile ?: (static.config.custom.configFile ?: “{lucee-server}/quartz/config.json”);
path = expandPath(path);
}
static.configFile = path;
ensureConfigFileExists(path);
return path;
}
…
2. Defensive Coding in
QuartzStore/Action.cfc
Pre-initialize variables.hasStorage = false;, variables.storage = “”;, and variables.storageLoaded = {}; at the top of overview(). If sendGatewayMessage fails, hasStorage is cleanly false rather than undefined.
3. Defensive Coding in
QuartzStore/overview.cfm
Change to <cfif hasStorage ?: false> so that an unhandled error does not crash the page template.
Render the session error banner above the block so the admin user sees the error message when a gateway failure occurs.

Thanks for the detailed report, Andrew — and for pushing past the surface error to the gateway logs.

This is actually three separate issues, so I’ve split them into tickets:

  • LDEV-6459 — the admin plugin crash. QuartzStore/overview.cfm references hasStorage before it’s guaranteed to be set, and that check sits above the error banner — so when the gateway call fails you get variable [HASSTORAGE] doesn't exist instead of the real message. That’s why the Jobs/Listeners/Storage panels look broken. Purely a frontend robustness bug in the extension. Heads-up: this code hasn’t changed in 1.0.0.56 / 1.0.0.57, so upgrading won’t fix it yet — the fix will come with these tickets.
  • LDEV-6460 — the underlying has no accessible Member with name [CONFIGFILE] error. One correction to the AI analysis: Lucee does keep a single persistent gateway CFC instance across init/start/sendMessage (via the gateway engine’s persistent-CFC cache), so state set in init() normally survives — static scope isn’t required. The real question is why init() didn’t take on the instance that later handled the message; I’m looking at the gateway’s init-exception handling and the template-caching workaround the extension currently needs.
  • LDEV-6461 — your question in the second post: whether an extension’s gateway CFC should be running under your application’s Application.cfc. Good catch; tracking the intended execution context there.

If you can attach the actual gateway.log / application.log from your Arch box to LDEV-6460, that’ll help pin down the init() failure.

This problem still exists on 1.0.0.65. Not sure what went into the latest version as the tickets are still open. If you need any testing or more info let me know.

Lucee 7.1.1.17-RC

Thanks Andrew, and sorry for the wait. We could reproduce both problems and they’re now fixed on the 1.0 and master branches:

  • LDEV-6459: the admin storage page crashed with “HASSTORAGE doesn’t exist” and hid the real error. All Quartz admin pages now show the actual cause.
  • LDEV-6460: the gateway failed with the CONFIGFILE error, also on fresh installs. Fixed.

LDEV-6461 (the gateway running under your Application.cfc) needs a change in Lucee itself and is tracked separately. In the meantime, that’s most likely the actual error you’ll now see in the admin.

The fixes will be in the next 1.0 snapshot, and I’ll post here once it’s available for you to test.

@apenhorwood the snapshot with the fixes is now available for testing:

If the admin still shows an error, it should now be the real cause. Please post it here, and thanks for testing!