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.