External script not working in Jira Data Center

I have a new external script (same location and permissions as existing external script), but when I try to use it in the Exalate outgoing script, it refuses to save.

import util.TextHelper //works
import util.WatcherHelper //does not work - imports additonal script in same package

This script imports another local script.

How do I resolve?

As an alternative, can I use httpclient in datacenter to interact with a scriptrunner endpoint?

It sounds like you’re running into issues importing a custom script (WatcherHelper) in your Exalate outgoing sync script on Jira Data Center, even though another script (TextHelper) in the same location works fine. Here are a few things to check and some alternatives:

  1. Script Import Issues
  • Double-check the file name and package declaration in WatcherHelper. The import path must match the package and file structure exactly.
  • Make sure WatcherHelper is saved in the correct directory and has the same permissions as TextHelper.
  • If WatcherHelper itself imports other scripts, ensure those dependencies are also present and accessible.
  1. Script Caching
    Sometimes, Jira Data Center or Exalate may cache scripts. Try restarting the Exalate node or clearing any script caches to ensure your new script is picked up.

  2. Script Syntax
    A syntax error in WatcherHelper can prevent it from being imported. Try running or compiling the script independently to check for errors.

  3. Using httpclient in Jira Data Center
    Yes, you can use httpClient in Exalate scripts on Jira Data Center to interact with external endpoints, including ScriptRunner REST endpoints. Here’s a basic example:

def response = httpClient.get("https://your-jira-instance/rest/scriptrunner/latest/custom/yourEndpoint")
    .header("Authorization", "Bearer your_token")
    .asString()
if (response.status == 200) {
    def result = response.body
    // process result
}

Make sure to handle authentication and SSL as needed for your environment.

For more details on using external scripts and httpClient in Exalate for Jira Data Center, check the documentation:

If you continue to have trouble, reviewing the logs for specific error messages when saving the script can help pinpoint the issue.

com.exalate.api.exception.script.ScriptException: No such property: httpClient for class: Script24 at com.exalate.error.services.ScriptExceptionCategoryService.categorizeProcessorAndIssueTrackerExceptionsIntoScriptExceptions(ScriptExceptionCategoryService.scala:51) at com.exalate.processor.ExalateProcessor.executeProcessor(ExalateProcessor.java:79) at com.exalate.processor.jira.JiraChangeIssueProcessor.executeChangeProcessor(JiraChangeIssueProcessor.java:288) at

Here’s a snippet of the error saying httpclient is not available

Hi @kibeh

Can you try this workaround ?

Can you please remove line

import util.WatcherHelper

and then paste WatcherHelper.groovy’s body straight into the exalate script editor and save. The editor reports the line/column, and that tells you immediately which of the four it is. If you can share the actual save error, I can point at the exact line.

Regarding httpClient alternative you asked:

There is no httpClient binding in Datacenter outgoing scripts —that’s a Jira Cloud thing

Thanks,

Sonal

import org.slf4j.LoggerFactory

import com.atlassian.jira.issue.Issue

import com.adaptavist.hapi.jira.users.Users

import com.adaptavist.hapi.jira.issues.Issues

import com.atlassian.jira.component.ComponentAccessor

That wouldn’t work as well because WatcherHelper also imports a bunch of ScriptRunner util classes, which I can’t post directly in the script

Hi @kibeh ,

What is probably happening

You have something like:

scripts/
├── TextHelper.groovy
└── WatcherHelper.groovy

and:

import util.TextHelper
import util.WatcherHelper

TextHelper works because it is probably independently resolvable by Exalate’s external-script classloader.

WatcherHelper is different because WatcherHelper.groovy itself has dependencies on ScriptRunner/HAPI classes, e.g.:

import org.slf4j.LoggerFactory
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor

So the problem isn’t necessarily the physical location or permissions of WatcherHelper.groovy. The problem is the dependency/classloading chain:

Exalate outgoing script
       ↓
WatcherHelper.groovy
       ↓
ScriptRunner / HAPI classes
       ↓
Jira / ScriptRunner classloader

The Exalate script editor’s validation/compiler doesn’t necessarily have access to that entire chain when it tries to save the processor.

Solution I’d recommend

Turn WatcherHelper into a compiled class/JAR and expose that to Exalate.

For example:

exalate-scripts/
    util/
        TextHelper.class
        WatcherHelper.class

or preferably:

exalate-scripts/
    watcher-helper.jar

with:

package util

class WatcherHelper {
    ...
}

Then your Exalate script remains clean:

import util.TextHelper
import util.WatcherHelper

// normal Exalate logic

This is actually aligned with Exalate’s documented external-script architecture: externalized scripts can include Groovy source, compiled classes, and packaged JARs.

The important part is that the compiled class/JAR must be built against the Jira/ScriptRunner libraries that exist on that particular Jira Data Center installation.

Let me know if this makes sense!

Thanks, Dhiren

Is there a documentation page I could use as a guide for this?

For now, I did find a workaround, but I’d prefer to resolve this without needing to parse information via the Jira issue comment