Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

“Inactive User” Error in Jira Automation

The Challenge

In our Jira setup, we use a custom field called “Visible to” to control who can view certain tickets. This field helps us ensure that only the right people have access to specific issues, despite adding them in Security Levels.

However, over time, we ran into a frustrating problem — when users became inactive, Jira automation rules started failing whenever they tried to add people to the “Visible to” field.

Why?
Because Jira doesn’t allow inactive users to be added to user picker fields, automation rules that referenced them would throw errors like:

“Unable to add user to field: user is inactive.”

This blocked our automation workflows and created unnecessary manual work just to remove those inactive users.


The Solution

To solve this, we wrote a script that identifies and removes all inactive users from a given user picker field — in our case, the “Visible to” field.

The script works as follows:

  1. It accepts a JQL query — for example, something like:

    project = "Support" AND "Visible to" is not EMPTY
  2. It searches for all issues matching the query.

  3. For each issue, it checks the “Visible to” field( or the field that we are providing in the script)

  4. It removes any inactive users from that field.

  5. It updates the issue, leaving only active users in the list.


Why This Helps

By running this cleanup script regularly (or even on demand), we:

  • Keep our “Visible to” field error-free.

  • Ensure automation rules don’t fail when updating user picker fields.

  • Maintain a cleaner, more reliable Jira environment.

This small utility script has saved us countless hours of debugging automation failures and makes our user management much smoother.

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.bc.user.search.UserSearchParams
// ====== CONFIGURE ======
final String FIELD_IDENTIFIER = "customfield_15501"   // User picker (single/multi)
final String JQL              = '"Visible to" in inactiveUsers() and project = "Support" and created >= 2025-10-09 and created <= 2025-10-10'    // adjust as needed
final String ACT_AS_USERNAME  = "jira.automation"
// ========================
// Resolve actor
def userManager = ComponentAccessor.userManager
def actingUser = Users.getByName(ACT_AS_USERNAME)
if (!actingUser) return "ERROR: Could not find user '${ACT_AS_USERNAME}'."
// Services
def issueManager       = ComponentAccessor.issueManager
def customFieldManager = ComponentAccessor.customFieldManager
def searchService      = ComponentAccessor.getComponent(SearchService)
def jqlParser          = ComponentAccessor.getComponent(JqlQueryParser)
def userSearchService  = ComponentAccessor.getComponent(UserSearchService)
// Get Field Object
CustomField cf = customFieldManager.getCustomFieldObject(FIELD_IDENTIFIER)
if (cf == null) return "ERROR: Field '${FIELD_IDENTIFIER}' not found."
// Parse + validate JQL
def query = jqlParser.parseQuery(JQL)
def validation = searchService.validateQuery(actingUser, query)
if (validation.hasAnyErrors()) {
    return "Invalid JQL: ${validation.getErrorMessages()}"
}
// Build explicit UserSearchParams (don't use variable name 'params')
def searchParams = UserSearchParams.builder()
    .allowEmptyQuery(true)
    .includeActive(true)
    .includeInactive(true)
    .maxResults(1000000)   // large value; adjust if needed
    .build()
// Now call findUsers with the searchParams
def allUsers = userSearchService.findUsers("", searchParams)
def inactiveUsers = allUsers.findAll { u -> u != null && !u.isActive() }
def inactiveIds = inactiveUsers.collect { u ->
    // some returned objects might not be ApplicationUser - safe cast
    try { (u as ApplicationUser).getId() as Long } catch (e) { null }
}.findAll { it != null } as Set<Long>
// Search issues
def results = searchService.search(actingUser, query, PagerFilter.unlimitedFilter)
def issues = results.getResults()
def updated = []
issues.each { issue ->
    MutableIssue mi = issueManager.getIssueByCurrentKey(issue.getKey())
    if (mi == null) return
    def fieldValue = mi.getCustomFieldValue(cf)
    if (fieldValue == null) return
    def currentUsers = (fieldValue instanceof Collection) ? fieldValue : [fieldValue]
    def kept = currentUsers.findAll { obj ->
        ApplicationUser u = (obj instanceof ApplicationUser) ? obj : null
        return (u != null && !inactiveIds.contains(u.getId() as Long))
    }
    if (kept.size() != currentUsers.size()) {
        def typeKey = cf.getCustomFieldType().getKey().toLowerCase()
        def isMulti = typeKey.contains("multi")
        mi.setCustomFieldValue(cf, isMulti ? kept : (kept ? kept[0] : null))
        issueManager.updateIssue(actingUser, mi, EventDispatchOption.ISSUE_UPDATED, false)
        updated << mi.getKey()
    }
}
return "✅ Removed inactive users from ${updated.size()} issues (acting as ${ACT_AS_USERNAME}). Issues: ${updated.join(', ')}"

1 comment

Stephen_Lugton
Community Champion
October 17, 2025

Thanks for the article @Gor Greyan , it was interesting to see how you got around the problem

Like # people like this

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events