Troubleshooting

How to Fix Lucee Migration Compatibility Issues

Overview of the Problem

Migrating CFML applications from Adobe ColdFusion (ACF) or older Lucee versions to a newer Lucee engine sometimes surfaces “compatibility issues.” These are behavior differences, missing Features (often due to uninstalled extensions), or Configuration mismatches that cause errors, broken Features, or Performance regressions after Deployment. They happen because Lucee and ACF are different CFML engines with distinct defaults, libraries, compilers, and extension ecosystems. Even migrating between Lucee versions (e.g., 5.3 → 5.4+ or 6.x) can introduce changes in null handling, JSON serialization, or driver behavior that affect your code.

Common symptoms include:

  • Tag/function not found (e.g., cfdocument, cfchart, ORM).
  • Query errors or query-of-queries differences.
  • Session/cookie behavior changes.
  • JSON casing differences.
  • Null handling or scope resolution errors.
  • Datasource connectivity or timezone/charset issues.
  • Missing custom tag mappings or Java libraries.

Why It Happens

Differences in engine behavior

  • Lucee deliberately differs from ACF in many areas (compiler, null semantics, JSON defaults, Security settings).
  • Major Lucee upgrades can change defaults (e.g., “Full Null Support” enabled introduces nuanced null behavior).

Extension-based features

  • PDF, Charting, ORM/Hibernate, Search, and others are extensions in Lucee, not core. If not installed, tags/functions will fail.

JVM/driver/library changes

  • Newer Lucee releases target newer Java versions and JDBC drivers, altering SQL parameter handling, timezones, TLS, and Performance.

Configuration drift

  • Admin-level settings (dialect, compatibility flags, encodings) and per-application settings (mappings, datasources, serialization) must be aligned with how your app expects to run.

Possible Causes

  • Missing extensions: PDF (cfdocument/cfpdf), ORM/Hibernate, Chart, Search.
  • Null support differences causing NPE-like issues and typecasting errors.
  • Datasource driver mismatch (e.g., switched from jTDS to Microsoft SQL Server driver) or missing connection parameters (timezone/charset).
  • JSON serialization differences (case preservation, date formatting).
  • Scope resolution/variable leakage differences (local vs variables/global).
  • Unconfigured mappings for components or Custom tags.
  • Query-of-Queries SQL differences, date comparisons, or type coercion issues.
  • Discontinued/unsupported features (e.g., CFX Custom tags).
  • Session/cookie configuration differences (SameSite, Secure, HTTPOnly).
  • File system path differences between environments (Windows vs Linux).
See also  How to Troubleshoot JVM Heap Dump Analysis for ColdFusion

Step-by-Step Troubleshooting Guide

1) Confirm your runtime matrix

  • Record versions: Lucee version, Java version, JVM args, OS, web server/connector.
  • Aim for Java that matches your Lucee stream (e.g., Lucee 5.4/6.x commonly run on Java 11 or 17; verify in release notes).
  • CommandBox tip:
    • box server start cfengine=lucee@6
    • server info to print engine and JVM details.

2) Reproduce and capture logs

  • Check these logs first:
    • Web context logs: WEB-INF/lucee/logs/
    • Server context logs: lucee-server/context/logs/
  • Typical files: application.log, exception.log, scheduler.log, mail.log.
  • Look for “missing extension” or “class not found” indicators.

Example:

ERROR application: missing tag [cfdocument]; please install extension [PDF Extension].
java.lang.ClassNotFoundException: org.lucee.extension.pdf.PDFService

Or null/type issues:

lucee.runtime.exp.ExpressionException: can’t cast [null] to a value of type [string]
at lucee.runtime.type.util.CastImpl.toString(CastImpl.java:…)

3) Verify Lucee Administrator settings

  • Server Admin > Settings > Language/Compiler:
    • Check “Null Support.” If your app wasn’t written for full null awareness, try disabling Full Null Support or explicitly handle nulls in code (see below).
  • Server Admin > Extensions:
    • Install required extensions (PDF, Chart, ORM, Search).
  • Server Admin > Services:
    • Mail server configured for cfmail? Verify and test.
  • Web Admin vs Server Admin:
    • Confirm which context your settings are applied to for your site.

4) Install missing extensions

  • PDF (cfdocument/cfpdf), Chart, ORM/Hibernate, Search/Solr or Lucene-like extension.
  • Admin > Extensions > Applications (or “Providers”): install and restart if required.
  • After installing ORM:
    • Enable in code: this.ormEnabled = true;
    • Initialize/clear: ORMReload();

5) Fix datasource configuration and drivers

  • Use modern JDBC drivers.

    • SQL Server: Microsoft driver preferred.
    • MySQL/MariaDB: Add serverTimezone=UTC and utf8mb4 charset.
  • Test DSNs in Admin. Turn on “Validate Connections.”

  • Example JDBC URLs:

    • SQL Server:
      jdbc:sqlserver://dbhost:1433;databaseName=MyDB;encrypt=true;trustServerCertificate=true
    • MySQL:
      jdbc:mysql://dbhost:3306/MyDB?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  • Ensure cfqueryparam types match real DB column types to avoid coercion errors.

6) Recreate mappings and custom tag paths

  • If you relied on server-level mappings in ACF, re-add them in Lucee or set per-application mappings in Application.cfc.

Example:
cfml
component {
this.mappings = {
“/lib” = expandPath(“/shared/lib”),
“/customtags” = expandPath(“/cfml/tags”)
};
}

7) Address language/compiler differences (nulls, scopes, QoQ)

  • Null handling:

    • Use structKeyExists(), isNull(), and elvis operator (?:) to handle nulls safely.
    • Guard against null function params and query cells:
      value = isNull(args.title) ? “” : args.title;
  • Scope resolution:

    • Prefer var/local scoping inside functions to avoid leakage.
    • Enable stricter scope resolution during development to catch implicit global lookups.
  • Query-of-Queries:

    • Simplify SQL; avoid DB-specific functions; cast dates explicitly or pre-normalize data.
    • If QoQ becomes fragile, execute the logic directly in the database via QueryExecute().

8) Align JSON serialization expectations

  • Preserve struct key case if needed:
    cfml
    component {
    this.serialization = { preserveCaseForStructKey = true };
    }

  • Be mindful of date serialization. Normalize dates to strings if callers depend on exact formatting.

9) File system and OS differences

  • Use expandPath(), getDirectoryFromPath(getCurrentTemplatePath()) for portability.
  • Avoid hard-coded drive letters and backslashes; prefer forward slashes in CFML.

10) Sessions and cookies

  • Review SameSite, Secure, HTTPOnly attributes—browsers enforce stricter cookie rules now.

  • If you relied on J2EE sessions or specific cookie names in ACF, test equivalent behavior in Lucee and adjust:
    cfml

  • Or let Lucee manage client cookies and configure in Admin or Application.cfc.

See also  How to Troubleshoot Out of Memory Errors in ColdFusion

11) Reintroduce caches and Scheduled tasks thoughtfully

  • Lucee cache engines differ from ACF. Configure default object/function/template caches in Admin, or via extension (EHCache-compatible, Redis, etc.).
  • Recreate Scheduled tasks in Lucee Administrator (or manage via code/CommandBox task runners).

Quick reference: Causes and Fixes

  • Cause: Missing PDF/Chart/ORM extension

    • Solution: Install from Lucee Admin > Extensions; restart if needed.
  • Cause: Null support differences causing runtime errors

    • Solution: Adjust Admin null setting or handle nulls explicitly with isNull(), Default values, and cfparam guards.
  • Cause: Datasource driver/timezone/charset misconfiguration

    • Solution: Update JDBC URL; add serverTimezone and UTF-8; match cfqueryparam types; test DSN.
  • Cause: JSON casing or date format changes

    • Solution: Set this.serialization.preserveCaseForStructKey=true; normalize date output.
  • Cause: Missing mappings/custom tag paths

    • Solution: Define this.mappings in Application.cfc or re-add globally in Admin.
  • Cause: QoQ Syntax/function differences

    • Solution: Simplify QoQ; cast data; or migrate logic into real DB queries.
  • Cause: Session/cookie behavior changes

    • Solution: Explicitly set SameSite/Secure/HTTPOnly; confirm Lucee session configuration.
  • Cause: Deprecated/unsupported features (CFX, Verity)

    • Solution: Replace with Java-based integrations, Lucee Search or Solr, and modern libraries.

Configuration Examples

Application.cfc baseline for Lucee

cfml
component {

this.name = “MyApp-Lucee”;
this.applicationTimeout = createTimeSpan(2,0,0,0);
this.sessionManagement = true;
this.sessionTimeout = createTimeSpan(0,2,0,0);
this.clientManagement = false;
this.setClientCookies = true;

this.charset = “UTF-8”;

// If you relied on case-sensitive JSON keys:
this.serialization = {
preserveCaseForStructKey = true
};

// Map libraries/components/custom tags:
this.mappings = {
“/lib” = expandPath(“/shared/lib”),
“/customtags” = expandPath(“/cfml/tags”)
};

// Datasource convenience (optional; still configure DSN in Admin if preferred)
this.datasource = “PrimaryDSN”;
this.datasources = {
PrimaryDSN = {
type = “mysql”,
host = “127.0.0.1”,
database = “appdb”,
port = 3306,
username = “dbuser”,
password = “secret”,
charset = “utf8mb4”,
timezone = “UTC”
}
};

// ORM (if needed; ensure extension installed)
// this.ormEnabled = true;

public boolean function onApplicationStart(){
return true;
}

public boolean function onRequestStart(string targetPage){
setLocale(“en_US”);
try { setTimeZone(“UTC”); } catch (any e) {}
return true;
}
}

CommandBox + CFConfig to migrate settings

  • Export from ACF, import into Lucee (datasources, mail, caches), then review in Admin:

box install commandbox-cfconfig
cfconfig export from=adobe file=./acfsettings.json
cfconfig import to=lucee file=./acfssettings.json

  • Start a local Lucee server for iterative testing:

box server start cfengine=lucee@5.4

  • Add to server.json relevant JVM args, webroot, and environment overrides as needed.

QueryExecute instead of QoQ (example)

cfml
// Prefer DB to avoid QoQ differences
q = queryExecute(
“SELECT id, name, created_at FROM users WHERE status = ? AND created_at >= ?”,
[ “active”, createDate(2023,1,1) ],
{ datasource = “PrimaryDSN” }
);

Detect missing PDF and fail fast

cfml
try {
// If cfdocument is used somewhere after this..
pdfExt = createObject(“java”,”org.lucee.extension.pdf.PDFService”);
} catch (any e) {
writeLog(file=”application”, text=”PDF Extension not installed: #e.message#”);
throw(message=”PDF Extension is required. Install via Lucee Admin > Extensions.”);
}


Common mistakes and How to Avoid Them

  • Assuming cfdocument/cfchart/ORM are “built-in”
    • Install the corresponding Lucee extensions and verify after restart.
  • Ignoring null-support differences
    • Audit high-risk areas (query cells, optional args, JSON parsing). Add null guards or adjust Admin setting during transition.
  • Using legacy JDBC drivers or missing connection parameters
    • Migrate to supported drivers (e.g., Microsoft SQL Server driver). Add timezone and charset for MySQL/MariaDB.
  • Skipping mappings recreation
    • Re-add component/custom tag mappings in Application.cfc or Admin; verify via getComponentMeta() or simple include tests.
  • Relying on QoQ for complex logic
    • Move complex filtering/aggregation to the database. Keep QoQ simple, with explicit casts.
  • Overlooking cookie and session policy changes
    • Set SameSite/Secure/HTTPOnly explicitly; test across iframes/third-party contexts if applicable.
  • Dropping Java libraries in the wrong location
    • Load via this.javaSettings or place JARs in Lucee’s recognized lib directories; restart to pick them up.
  • Not reading logs
    • application.log and exception.log usually point directly to missing extensions/config mismatches.
See also  How to Fix ColdFusion on Docker Container Startup Failures

Prevention Tips / Best practices

  • Maintain a staging environment with the same Lucee and Java versions as production.
  • Make compatibility explicit in code:
    • Guard nulls, specify JSON casing, define mappings per app, use cfqueryparam consistently.
  • Adopt automated tests (TestBox/Integration tests) and run them under Lucee before cutover.
  • Prefer explicit database queries over complex QoQ.
  • Keep a Migration Checklist: extensions installed, DSNs tested, caches configured, schedulers recreated, mail verified.
  • Use CommandBox for reproducible local servers and CFConfig for portable Admin settings.
  • Pin versions (Lucee engine, extensions, JDBC drivers) and upgrade intentionally with release notes.
  • Document non-default admin settings and per-application overrides in Version control.

Key Takeaways

  • Most Lucee Migration problems trace to missing extensions, null-handling differences, and DSN/driver changes.
  • Read the logs first; they often identify the exact missing piece.
  • Install required extensions (PDF/ORM/Chart/Search) and verify with a minimal repro.
  • Normalize datasource settings (timezone, charset) and prefer modern drivers.
  • Make behavior explicit in Application.cfc (mappings, serialization, sessions) and in code (cfqueryparam, null guards).
  • Use CommandBox + CFConfig to move and version your Server settings safely.

FAQ

How do I quickly tell if null support is causing my errors?

Look for errors about casting null to string/number or unexpected isNull behavior. Temporarily disable Full Null Support in Lucee Admin > Settings > Language/Compiler, or add targeted guards (isNull(), cfparam defaults) where failures occur. If issues disappear, plan a controlled null-handling strategy in your code.

Why do cfdocument or cfchart throw “tag not found” After migration?

In Lucee, PDF and Chart features are extensions, not core. Install them via Lucee Administrator > Extensions. After installation, restart the context and re-test.

My query-of-queries worked in ACF but fails in Lucee. What should I change?

Simplify QoQ Syntax, avoid DB-specific functions, and cast types explicitly. If it’s still brittle, move the logic into a real database query using QueryExecute(). Lucee’s QoQ has different constraints than ACF.

JSON keys changed case in responses. How can I restore previous behavior?

Set this.serialization.preserveCaseForStructKey = true in Application.cfc. If clients rely on specific formats, also normalize dates/numbers to strings before serializeJSON().

Does Lucee support CFX tags or Verity collections?

CFX native tags are not supported. Replace them with Java-based CFML integrations or modern libraries. Verity is discontinued; switch to Lucee Search/Solr or a modern search stack (e.g., Elasticsearch) and adapt your code accordingly.

About the author

Aaron Longnion

Aaron Longnion

Hey there! I'm Aaron Longnion — an Internet technologist, web software engineer, and ColdFusion expert with more than 24 years of experience. Over the years, I've had the privilege of working with some of the most exciting and fast-growing companies out there, including lynda.com, HomeAway, landsofamerica.com (CoStar Group), and Adobe.com.

I'm a full-stack developer at heart, but what really drives me is designing and building internet architectures that are highly scalable, cost-effective, and fault-tolerant — solutions built to handle rapid growth and stay ahead of the curve.