Start/Stop Mailpit with CommandBox Server Start/Stop

I use Mailpit to capture email while developing CFML applications locally. It works great, but I don’t necessarily need it running all the time. Since I already use CommandBox to start and stop my local ColdFusion server, I wanted Mailpit to follow the same lifecycle.

Fortunately, CommandBox server scripts make this straightforward. When the CommandBox server starts, it can start Mailpit. When the server stops, it can stop Mailpit as well.

Prerequisites

This example is for macOS and assumes Mailpit was installed with Homebrew:

brew install mailpit

You can test Mailpit manually with:

brew services start mailpit
brew services stop mailpit

By default, Mailpit provides:

CommandBox server lifecycle scripts

CommandBox supports server-specific scripts in server.json. Among the available lifecycle events are:

  • onServerStart, which runs while the server is starting
  • onServerStop, which runs before the server stops

Add the following top-level scripts object to the CommandBox server configuration:

{
    "scripts": {
        "onServerStart": "!brew services start mailpit",
        "onServerStop": "!brew services stop mailpit"
    }
}

The ! prefix tells CommandBox to execute a native operating-system command.

If CommandBox cannot find Homebrew in its PATH, use the full path to the executable. On an Apple Silicon Mac, that will commonly be /opt/homebrew/bin/brew:

{
    "scripts": {
        "onServerStart": "!/opt/homebrew/bin/brew services start mailpit",
        "onServerStop": "!/opt/homebrew/bin/brew services stop mailpit"
    }
}

On an Intel Mac, Homebrew is commonly located at /usr/local/bin/brew. Run which brew in Terminal to confirm the correct path.

Wait until Mailpit is ready

Starting the Homebrew service does not necessarily mean Mailpit is ready to accept requests at that exact instant. Mailpit provides /readyz for checking its readiness. A successful request returns an HTTP 200 response.

We can make the startup script check that endpoint once per second for up to 20 seconds:

{
    "scripts": {
        "onServerStart": [
            "!brew services start mailpit",
            "!for i in {1..20}; do curl -fsS http://127.0.0.1:8025/readyz && exit 0; sleep 1; done; echo 'Mailpit failed to become ready' >&2; exit 1"
        ],
        "onServerStop": "!brew services stop mailpit"
    }
}

This script:

  1. Starts Mailpit through Homebrew.
  2. Checks the Mailpit readiness endpoint.
  3. Continues as soon as Mailpit responds successfully.
  4. Returns an error if Mailpit does not become ready within 20 seconds.

You can also check Mailpit manually at any time:

curl -fsS http://127.0.0.1:8025/readyz

To inspect the Homebrew service state instead, run:

brew services info mailpit

Show Mailpit’s status on a local home page

My CommandBox server hosts several local applications, so I have a simple home page that links to each application and development resource. I wanted its Mailpit card to show whether Mailpit was online.

When Mailpit is stopped, the card displays a red Offline badge:

Mailpit Offline
Mailpit Offline

When Mailpit is available, it displays a green Online badge:

Mailpit Online
Mailpit Online

First, check the readiness endpoint near the beginning of the CFML page, before the HTML output:

<cfset mailpitOnline = false>

<cftry>
    <cfhttp
        url="http://127.0.0.1:8025/readyz"
        method="GET"
        timeout="2"
        result="mailpitHealth">

    <cfset mailpitOnline = val(mailpitHealth.statusCode) eq 200>

    <cfcatch type="any">
        <cfset mailpitOnline = false>
    </cfcatch>
</cftry>

The default value is false. If Mailpit responds with HTTP status 200, it changes to true. A timeout or connection error is caught so an unavailable Mailpit service does not cause the home page itself to fail.

The two-second timeout also prevents the check from delaying the page for too long.

Next, use that value to set the card’s border and status badge:

<div class="col-6 col-md-4 col-lg-3">
    <a href="http://localhost:8025" class="text-decoration-none" target="_blank">
        <div class="card h-100 shadow-sm <cfif mailpitOnline>border-success<cfelse>border-danger</cfif>">
            <div class="card-body text-center">
                <h5 class="card-title text-secondary">
                    Mailpit
                    <cfif mailpitOnline>
                        <span class="badge text-bg-success align-middle"
                              style="font-size: 0.6rem;">Online</span>
                    <cfelse>
                        <span class="badge text-bg-danger align-middle"
                              style="font-size: 0.6rem;">Offline</span>
                    </cfif>
                </h5>
            </div>
        </div>
    </a>
</div>

This example uses Bootstrap 5 classes for the card, border, and badge styling.

Putting it all together

The final CommandBox configuration is:

"scripts": {
    "onServerStart": [
        "!brew services start mailpit",
        "!for i in {1..20}; do curl -fsS http://127.0.0.1:8025/readyz && exit 0; sleep 1; done; echo 'Mailpit failed to become ready' >&2; exit 1"
    ],
    "onServerStop": "!brew services stop mailpit"
}

Now Mailpit starts along with the CommandBox server, its readiness is verified, and the local home page indicates whether it is online. When the CommandBox server is stopped normally, Mailpit is stopped as well.

A few things to keep in mind

  • The stop hook runs when the server is stopped through CommandBox. It cannot run if CommandBox is force-terminated or the computer shuts down unexpectedly.
  • Homebrew services are user-wide. If several CommandBox servers or other applications share the same Mailpit instance, stopping one server could stop Mailpit while something else is using it.
  • If one CommandBox server hosts several applications, put the scripts in that server’s shared configuration. Mailpit will then follow the lifecycle of the entire server rather than any single application.
  • The status badge reflects Mailpit’s state when the CFML page is rendered. Refresh the page to update it.

That’s it. Mailpit is available when the local development server is running and gets out of the way when development is finished.

Add items (like Mailpit or tailing logs) to the CommandBox Tray

I’ve always been a fan of the tray that’s available when CommandBox launches. On the Mac, it appears as a menu bar icon in the top menu (first icon below).

CommandBox menu bar icon
CommandBox menu bar icon

It has some very convenient built-in options:

Servername
├── Stop Server
├── Restart Server
├── Open...
│   ├── Webroot
│   ├── Server Home
│   ├── Site Home
│   └── Server Admin
├── Info
│   ├── Engine: adobe 2023.0.17+330864
│   ├── Webroot: /Path/to/website/
│   ├── URL: https://127.0.0.1:8443
│   ├── PID: 99999
│   └── Heap: Not set

I frequently need to access Mailpit and various log files as I work through the development process on a current project. This got me wondering if I could add some of my own frequently accessed items to the tray. It turns out you can add quite a few different things.

Enable the tray

First, enable the tray in the server.json file for the site.

"trayEnable": true,

Next, let’s start simple and add a single item to open Mailpit in a browser. The trayOptions setting accepts an array of objects. Each object should contain a label, an action, and one of [url, path, command]. The label is the text that appears in the tray. The action tells CommandBox what to perform (openbrowseropenfilesystemrunAsync, etc.). The [url, path, command] values provide the URL of the site, the filesystem path, or the command to execute, respectively.

Setting the tray options

"trayOptions": [
    {
        "label": "Mailpit Web Interface",
        "action": "openbrowser",
        "url": "http://localhost:8025"
    }
]

Let’s dive a little deeper with some other options.

Add a “divider” of blank space between CommandBox’s built-in options and the ones we are adding.

{
    "label": " ",
    "disabled": true
}

Open a folder on the filesystem.

{
    "label": "Open Log Folder",
    "action": "openfilesystem",
    "path": "${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs"
}

Tail the last 100 lines of mailsent.log (macOS only as written, but adaptable for Linux or Windows).

{
    "label": "Tail mailsent.log",
    "action": "runAsync",
    "command": "tmpfile=$(mktemp -t tail-mailsent).command; printf '#!/bin/zsh\nprintf \"\\e]0;Tail mailsent.log\\a\"\nclear\ntail -n 100 -f \"%s\"\n' '${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs/mailsent.log' > \"$tmpfile\"; chmod +x \"$tmpfile\"; open -a Terminal \"$tmpfile\""
}

Explanation of the tail command

Add some icons using emojis.

🛠 Development Tools
📬 Mailpit Web Interface
📂 Logs

Putting it all together

CommandBox tray open
CommandBox tray open
"trayEnable": true,
"trayOptions": [
    {
        "label": " ",
        "disabled": true
    },
    {
        "label": "🛠 Development Tools",
        "items": [
            {
                "label": "📬 Mailpit Web Interface",
                "action": "openbrowser",
                "url": "http://localhost:8025"
            },
            {
                "label": "📂 Logs",
                "items": [
                    {
                        "label": "Open Log Folder",
                        "action": "openfilesystem",
                        "path": "${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs"
                    },
                    {
                        "label": "Tail application.log",
                        "action": "runAsync",
                        "command": "tmpfile=$(mktemp -t tail-application).command; printf '#!/bin/zsh\nclear\ntail -n 100 -f \"%s\"\n' '${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs/application.log' > \"$tmpfile\"; chmod +x \"$tmpfile\"; open -a Terminal \"$tmpfile\""
                    },
                    {
                        "label": "Tail exception.log",
                        "action": "runAsync",
                        "command": "tmpfile=$(mktemp -t tail-exception).command; printf '#!/bin/zsh\nclear\ntail -n 100 -f \"%s\"\n' '${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs/exception.log' > \"$tmpfile\"; chmod +x \"$tmpfile\"; open -a Terminal \"$tmpfile\""
                    },
                    {
                        "label": "Tail mailsent.log",
                        "action": "runAsync",
                        "command": "tmpfile=$(mktemp -t tail-mailsent).command; printf '#!/bin/zsh\nprintf \"\\e]0;Tail mailsent.log\\a\"\nclear\ntail -n 100 -f \"%s\"\n' '${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs/mailsent.log' > \"$tmpfile\"; chmod +x \"$tmpfile\"; open -a Terminal \"$tmpfile\""
                    }
                ]
            }
        ]
    }
]

Explanation of the tail command

This command creates a temporary shell script, makes it executable, and opens it in Terminal. Reminder: this version is macOS only as written because it uses zshmktemp, and open -a Terminal.

"command": "tmpfile=$(mktemp -t tail-mailsent).command; printf '#!/bin/zsh\nprintf \"\\e]0;Tail mailsent.log\\a\"\nclear\ntail -n 100 -f \"%s\"\n' '${serverinfo.serverHomeDirectory}/WEB-INF/cfusion/logs/mailsent.log' > \"$tmpfile\"; chmod +x \"$tmpfile\"; open -a Terminal \"$tmpfile\""

What it does

  • mktemp -t tail-mailsent
    • Creates a uniquely named temporary file.
  • printf '#!/bin/zsh ...'
    • Writes a small shell script into the temporary file.
  • printf "\e]0;Tail mailsent.log\a"
    • Sets the Terminal window title.
  • clear
    • Clears the Terminal window before output begins.
  • tail -n 100 -f
    • Displays the last 100 lines of the log file and continues following new entries in real time.
  • chmod +x
    • Makes the temporary script executable.
  • open -a Terminal
    • Opens the script in the macOS Terminal application.

Next Steps

There are all kinds of other tasks that could be added to the tray such as:

  • Ping a server
  • Flushing DNS
  • Open the hosts file to edit
  • Open the site’s Git repo

Good luck!

Mailpit + ColdFusion Local Email Testing

Overview

This article documents how to configure Adobe ColdFusion to use Mailpit for local email testing.

Mailpit captures outbound email locally so messages can be reviewed in a browser without sending real email.


Export Existing Mail Settings (Optional)

Before making changes, export the current ColdFusion mail configuration so it can be restored later if needed.

cfconfig export from=server.local to=mailSettings.json includeList=mailservers**

Example exported configuration:

{
    "mailServers": [
        {
            "tls": true,
            "password": "SUPERSECRET",
            "port": 587,
            "username": "USERNAME",
            "ssl": false,
            "smtp": "smtp.mailgun.org"
        }
    ]
}

Install Mailpit

Install Mailpit using Homebrew.

brew install mailpit

Start Mailpit

Start the Mailpit service.

brew services start mailpit

Configure ColdFusion to Use Mailpit

Method 1: Configure with CommandBox

Create a file named mailSettingsMailpit.json.

{
    "mailServers": [
        {
            "tls": false,
            "password": "",
            "port": 1025,
            "username": "",
            "ssl": false,
            "smtp": "127.0.0.1"
        }
    ]
}

Import the Mailpit configuration into ColdFusion.

cfconfig import from=mailSettingsMailpit.json to=server.local

Method 2: Configure in ColdFusion Administrator

Navigate to:

ColdFusion Administrator → Server Settings → Mail

Configure the following values:

Mail Server: 127.0.0.1
Server Port: 1025
Username: blank
Password: blank
Use TLS: unchecked
Use SSL: unchecked

Test Email Delivery

Create a .cfm test page.

<cfscript>
    recipientCount = 5;

    for (i = 1; i <= recipientCount; i++) {

        recipient = "foo#i#@bar.com";

        cfmail(
            to = recipient,
            from = "[email protected]",
            subject = "Mailpit Test",
            type = "html"
        ) {

            writeOutput("
                <h1>Hello from ColdFusion</h1>
                <p>
                    It is #dateFormat(now(), 'mm/dd/yyyy')# at
                    #dateTimeFormat(now(), 'hh:mm:ss tt')#.
                    This should show up in Mailpit.
                </p>
            ");
        }

        sleep(3000);

        writeOutput("<p>Mail sent.</p>");
    }

    writeOutput('<p><a href="#cgi.script_name#">Run again</a></p>');
</cfscript>

Verify Email Delivery

Open the Mailpit web interface:

http://localhost:8025

The test emails should appear in the Mailpit inbox.

Mailpit inbox
Mailpit inbox

Restore Original Mail Settings (Optional)

Restore the original ColdFusion mail configuration.

cfconfig import from=mailSettings.json to=server.local

Restart ColdFusion after restoring the configuration if required.


Stop Mailpit

Stop the Mailpit service.

brew services stop mailpit

Running ColdFusion (ACF or Lucee) on Raspberry Pi 5

It’s been ages since I have had the time to tinker with any of my Raspberry Pis. In fact playing old games with my son using Retro Pi is probably 90% of the interaction in the last 3-4 years. Last week I was cleaning up some old “tech stuff” around my home office and came across my Raspberry Pi 5 unplugged and shelved. Barely an hour later I was running ColdFusion on it (of course by way of CommandBox).

I’m not going to go through all the details on how to get a Raspberry Pi up and running. There are plenty of videos and tutorials for that. What I’d like to
provide is a slight update to the 4 commands necessary to install CommandBox on the current OS – Raspbian GNU/Linux 13 (trixie). I found this in the Linux apt-get → Stable section of the CommandBox documentation. I added the comments.

    # 1. Downloads Ortus Solutions' repository GPG signing key,
    #    converts it to a trusted keyring format, and installs it
    #    so your system can verify packages from that repo are authentic.
    curl -fsSl https://downloads.ortussolutions.com/debs/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/ortussolutions.gpg > /dev/null


    # 2. Adds the Ortus Solutions package repository to your system's
    #    APT software sources list.
    echo "deb [signed-by=/usr/share/keyrings/ortussolutions.gpg] https://downloads.ortussolutions.com/debs/noarch /" \
    | sudo tee /etc/apt/sources.list.d/commandbox.list


    # 3. Refreshes the package index and installs CommandBox
    #    (plus HTTPS support for APT if needed).
    sudo apt-get update && sudo apt-get install apt-transport-https commandbox

    # 4. Install Java
    sudo apt install default-jdk

Number 4 is really my only contribution here. The original command: sudo apt install openjdk-11-jdk results in an error since
openjdk-11-jdk no longer exists in the main repository. The command I provided installs the default which at the time of this writing is
openjdk-21. Below you can see the output of the original command and the updated one.

Install Java
Install Java

Once CommandBox was installed I fired up an instance of Adobe ColdFusion 2025. Screenshot was taken using Raspberry Pi Connect screen sharing. As a side note I
showed server.os.additionalInformation for ACF since server.os.name reports as UNIX.

ACF ColdFusion on Raspberry Pi 5
ACF ColdFusion on Raspberry Pi 5

Also fired up an instance of Lucee 5. Screenshot taken again using Raspberry Pi Connect screen sharing.

Lucee ColdFusion on Raspberry Pi 5
Lucee ColdFusion on Raspberry Pi 5

I guess I’ve been away from the Raspberry Pi game for so long that I was pretty blown away by the new Raspberry Pi Connect remote-access service from the Raspberry Pi Foundation. This service lets you open and control your Raspberry Pi desktop from anywhere through a web browser — without port-forwarding, VPNs, or knowing your home IP address.

Also of note, the Raspberry Pi Imager is amazing. You can preconfigure settings such as WiFi network access, VNC, Hostname, and other settings as you create the image rather than digging around in config files or using raspi-config after the fact.

Better Comments extension for CFML development in VSCode

This is an example of using the Better Comments extension for CFML development in VSCode .

The Better Comments extension visually highlights specially tagged comments (like TODO, !, or ?) using colors and styles so important notes, questions, and tasks stand out instantly in your code.

You can define custom styles in either User or Workspace settings.json. You can set the color or backgroundColor, as well as underline, strikethrough, bold, and italic.

Example of a custom LUCEEONLY comment:

    "better-comments.tags": [
        {
            "tag": "luceeonly",
            "color": "#3CBED0",
            "strikethrough": false,
            "underline": false,
            "backgroundColor": "#transparent",
            "bold": true,
            "italic": false
        }
    ]

Gotcha 1: You must define all better-comments.tags in one location. Better Comments does not merge tag arrays.

Gotcha 2: When using CFML block comments in tag-based ColdFusion files, you must use // as the first non-whitespace characters after the opening comment tag for Better Comments to recognize the comment type.

Changes to settings may require reloading the VS Code window to take effect:

CMD+SHIFT+P > Developer: Reload Window

Results below:

Better Comments extension for CFML development in VSCode
Better Comments extension for CFML development in VSCode

ColdFusion Hash() Defaults Changed — Here’s How to Fix It With Regex

Starting with ColdFusion 2021 Update 14 and ColdFusion 2023 Update 8, the default hashing algorithm changed from CFMX_COMPAT to SHA-256.

Any code relying on Hash(value) without explicitly specifying the algorithm can:

  • Behave differently after an upgrade
  • Break verification logic
  • Trigger security scanner findings (Fixinator)

Fixinator provides the following warning:

Use of a weak hashing algorithm such as MD5 (the algorithm used by CFMX_COMPAT). This can also be a compatibility issue (after CF2023 update 8 and CF2021 update 14) if the hash algorithm is not specified. The default has changed from CFMX_COMPAT to SHA-256 in those releases.
In CFML, Hash() can appear in two contexts:
  1. Output expressions: #Hash(value)#
  2. Script/logic: Hash(value)

Any global refactor must account for both forms. It took me a few iterations to get what I needed.

This article demonstrates how to perform a global search and replace using REGEX in VS Code.

Note(s):

  • In the VS Code search panel REGEX is enabled with the .* icon to the right of the search input.
  • The ColdFusion app I was working with used only Hash() and not hash().
  • You could use a case insensitive search with the REGEX from Iteration 3 with “Preserve Case” for the replace input to account for Hash() vs hash() if necessary.
  • Your mileage may vary on this solution.

WARNING

PLEASE PREVIEW THE RESULTS OF YOUR SEARCHES BEFORE DOING THE REPLACE.


Iteration 1

This was my first attempt.

Search: #Hash\(\s*([^)]*?)\s*\)#
Replace: #Hash($1, "SHA-256", "UTF-8")#
Bad Match: <a href="edit.cfm?newsID=#qData.newsID#&verifyID=#Hash(qData.newsID, ">Edit</a>
Bad Result: <a href="edit.cfm?newsID=#qData.newsID#&verifyID=#Hash(qData.newsID, ">Edit</a>
Why it’s bad: Caused incorrect code if the algorithm argument already existed.

Iteration 2

Based on the failure of the first attempt I made the following second attempt.

Search: #Hash\(\s*([^,\)]+)\s*\)#
Replace: #Hash($1, "SHA-256", "UTF-8")#
Missed Match:

<cfif Hash(URL.newsID) EQ URL.newsID>
...
</cfif>

Why it’s bad: No match when there were no pound signs (ie Script/logic not output)

Iteration 3

Third time is a charm!

Search: \bHash\(\s*([^,\)\r\n]+?)\s*\)
Replace: Hash($1, "SHA-256", "UTF-8")

cfhash search and replace regex
cfhash search and replace with regex vscode screenshot

Conclusion

YAY! This result yielded 206 corrections throughout the app that would have taken a long time to correct without a REGEX search and replace. This legacy app is 20+ years old so the first goal was compatibility. In a follow up article I’ll look at improving security with HMAC.

Note

This post was amended from “the default hashing algorithm changed from MD5 to SHA-256” to “the default hashing algorithm changed from CFMX_COMPAT to SHA-256”. Even though they do the same thing the default was technically CFMX_COMPAT.

Set CommandBox to the default terminal profile in VSCode terminal

Here is a helpful workspace configuration option(s) that allows you to set the default terminal profile (terminal.integrated.defaultProfile.YOUR_OS) to CommandBox in VSCode terminal.  This allows you to launch CommandBox by default when you open a terminal in the workspace.  Further, you can specify the current working directory (terminal.integrated.cwd) so any new terminal you open in the workspace will start in that directory.

On OSX

"settings": {
  "terminal.integrated.profiles.osx": {
    "CommandBox": {
      "path": "/Users/csimmons/.CommandBox/bin/box"
    }
  },
  "terminal.integrated.defaultProfile.osx": "CommandBox",
  "terminal.integrated.cwd": "/Users/csimmons/websites/demos"
}

On Windows

"settings": {
  "terminal.integrated.profiles.windows": {
    "CommandBox": {
      "path": "C:\\Users\\csimmons\\.CommandBox\\box.exe"
    }
  },
  "terminal.integrated.defaultProfile.windows": "CommandBox",
  "terminal.integrated.cwd": "C:\\Users\\csimmons\\websites\\demos"
}

Note(s)

  • These settings are stored in YOUR_WORKSPACE.code-workspace so you can set them on a per workspace basis.
  • YOUR_OS = the OS you are running
  • YOUR_WORKSPACE = whatever the .workspace file is for your current workspace.

This post is a follow up to a topic I originally posted titled Run CommandBox directly inside VSCode Terminal which explained setting up a custom terminal profile (terminal.integrated.profiles.YOUR_OS) for CommandBox.

Revisiting CFML Formatter (VSCode extension) with cfformat-ignore

I’d like to revisit the CFML Formatter (VSCode extension) that I posted on not too long ago and mention the cfformat-ignore functionality.

I had to work on some 15+ year old code today. I won’t say who wrote that code. Cough Me. Cough Embarrassing. Every time I saved a file the CFML Formatter was working overtime to try to figure out how to get the code formatted. Long story short there were a few blocks involving concatenation that ended up throwing errors after they were reformatted. Due to time constraints I needed to put a pin in figuring how to rewrite the offending blocks and just needed cfformat to ignore those blocks.

In a nutshell there are 3 ways to do it depending on the block of code.

Tag Based

Script Based

Comment Block

    /* cfformat-ignore-start */
    /* Crazy, unformatted code here. */
    /* cfformat-ignore-end */

Note: The special cfformat-ignore-start and cfformat-ignore-end comments must be at the same level of indentation within the file to work properly.

ColdFusion 2021 Update 20 – “does not support _ as an argument” error with Ajax Autocomplete for jQuery

ColdFusion (2021 release) Update 20 recently broke multiple autosuggest fields across my organization’s web applications. ColdFusion (2023 release) Update 14 causes the same issue.

Many of our organization’s autosuggest fields utilize Ajax Autocomplete for jQuery. This jQuery plugin retrieves data from a ColdFusion cfc to populate a field as a user enters data.

The frustrating thing for the end user is that the autosuggest fields simply stopped working so there was no error for them to report.

The first step used to troubleshoot the issue was to head over to our Dev environment and fire up Chrome’s Developer Tools and try to use an autosuggest field. The result was a Failed to load resource error in the Console tab.

Failed to load resource: the server responded with a status of 500 (Internal Server Error)
Failed to load resource: the server responded with a status of 500 (Internal Server Error)

The next step was to move to the Network tab, locate the url of the call to the cfc, right click and choose “Open in new tab”. The following error was the result.

ColdFusion error: does not support _ as an argument
ColdFusion error: does not support _ as an argument

I saw a nearly identical error message post Update 20 where there was a mismatch in the number of arguments passed to a method in an older cfc in one of our web applications. In that instance, instead of _ the argument being passed was the actual name of a field which was no longer an argument in the method of the cfc so I knew there was an argument mismatch, but what the heck was this _ argument?

The _ argument is appended to the URL by jQuery if you use $.ajaxSetup({ cache: false });. It is a jQuery global configuration that disables caching for all subsequent AJAX GET requests made via jQuery by appending a unique query parameter (like _={timestamp}) to each request URL.

    https://demos.local/cfcs/room.cfc?method=getRoomAutoComplete&query=Lab&_=1753998286050

There are 2 ways to fix this issue in ColdFusion or 2 ways to fix it via JavaScript.

ColdFusion Solution 1 – Fix the argument mismatch

Update the method used by autosuggest, in our case getRoomAutoComplete(), to include an argument named _:

    remote any function getRoomAutoComplete(required string query, string _) returnformat="plain" {
        ...
    }

ColdFusion Solution 2 A- Override the new feature (ColdFusion Administrator)

In the ColdFusion Administrator search for “Java & JVM” (or in jvm.config) add:

    -Dcoldfusion.runtime.remotemethod.matchArguments=false and restart CF services.

ColdFusion Solution 2 B – Override the new feature (CommandBox)

If you’re using CommandBox add the following to your server.json file:

    "jvm":{
        "args":[
        "-Dcoldfusion.runtime.remotemethod.matchArguments=false"
        ]
    }

JavaScript Solution 1 – Avoid disabling caching globally in JavaScript

Avoid using the following to disable caching globally in your JavaScript:

    $.ajaxSetup({ cache: false });

JavaScript Solution 2 – Override caching globally in JavaScript

If you must disable caching globally in your JavaScript, you can override it for Autocomplete using the following:

    ajaxSettings: {
        cache: true
    }

Read more

JVM arguments in 2023 and 2021 updates of ColdFusion

ColdFusion 2021 Update 19 – Administrator Not Installed and toInstallBundles.txt (Access is Denied) Issue

I administer two servers running ColdFusion 2021. One of them is on a VPS. The other is on a VM in a highly restricted internal environment. For both servers the following manual install method is used for updates.

  1. Stop the ColdFusion service.
  2. Run the command prompt as administrator then execute:
    C:\ColdFusion2021\jre\bin\java -jar C:\Path\To\hotfix\hotfix-019-330379.jar
  3. Follow the GUI installer prompts until the install is completed.
  4. Restart the ColdFusion service.
  5. Login to the CFAdmin and verify the version on the System Information page.

Everything went fine for the VPS. When I tried to login to the CFAdmin on the internal server after the upgrade, however, I was greeted with the following error:

Update 19 install administrator error
Update 19 install administrator error

This error message occurs when you attempt to execute functionality that depends on a package that has not been installed. Kind of odd in this case since the administrator package was previously installed, but since I’ve seen this once before it didn’t seem that concerning. I launched the ColdFusion Package Manager by navigating to C:\ColdFusion2021\bin\ and executing cfpm.bat. Then I ran install administrator as suggested in the error message. I received the following error(s) in the cfpm prompt.

Update 19 cfpm install administrator error 1
Update 19 cfpm install administrator error 1

I’ve actually seen this error before on the internal server:
The packages repository https://www.adobe.com/go/coldfusion-packages is not accessible.
The second part of the error contained the tip I used to resolve it previously:
You can only load the packages that are available locally in the C:\ColdFusion2021\bundles directory.
As I did previously I went to the C:\ColdFusion2021\bundles directory on our other server and copied the administrator package files and placed them in the same location on the internal server:

  • administrator-2021.0.19.330379.jar
  • administrator-2021.0.19.330379.zip

I ran install administrator again. The package seemed to install, however, the error regarding toInstallBundles.txt remained.

Update 19 cfpm install administrator error 2
Update 19 cfpm install administrator error 2

I was still unable to access CFAdmin with the same The administrator is not installed error so I navigated to the C:\ColdFusion2021\cfusion\lib\toInstallBundles.txt file and checked the properties and it seemed as though the account running ColdFusion had read/write access to it. I moved the file to the desktop and then moved it back.

I ran install administrator again and this time there were no errors and CFAdmin was installed and accessible.

Any thoughts on a better way to handle/prevent these errors in future upgrades?