---
title: "Creating a character limit validator in Jira Cloud with JMWE"
canonical: "https://support.appfire.com/space/SUPPORT/3001778177/Creating%20a%20character%20limit%20validator%20in%20Jira%20Cloud%20with%20JMWE"
format: markdown
---
Purpose: Create a workflow Validator in Jira Cloud (using Jira Misc Workflow Extensions - JMWE) that blocks a transition when a Paragraph/Multi-line Text field exceeds a maximum number of characters.

## Overview

In Jira Cloud, rich-text (paragraph) fields are stored as a nested content structure rather than a plain string. That's why a simple length comparison fails. This guide shows how to build a Jira Expression-based Validator in JMWE that traverses the paragraph structure, sums all text node lengths, and enforces a character limit.

Applies to: Jira Cloud + JMWE. You'll need Workflow edit permissions and the custom field's ID (for example, customfield_12345).

## Prerequisites

- JMWE app installed on Jira Cloud
- A Paragraph or Multi-line Text custom field already created
- Workflow transition where you want to enforce the limit

## Step-by-step: add the validator

1. Open the target workflow in Jira Cloud (Project settings > Workflows), switch to the Diagram view, and select the transition to validate.
2. Add a Validator: choose **Build-your-own (scripted) Validator** and set the Validator type to **Jira Expression**. For more details, see [https://appfire.atlassian.net/wiki/spaces/MWECS/pages/449315100](https://appfire.atlassian.net/wiki/spaces/MWECS/pages/449315100).
3. Paste the expression below, replacing customfield_XXXXX with your field ID and 110 with your desired max length.
4. Configure the error message shown to users when the limit is exceeded.
5. Publish the workflow and test the transition.

## Jira expression (validator)

```javascript
issue.customfield_XXXXX != null &&
(
  issue.customfield_XXXXX.content
    .flatMap(p => p.content)
    .filter(n => n.text != null)
    .map(n => n.text.length)
    .reduce((sum, len) => sum + len, 0)
) <= 110
```

Tip: Document the character limit you've chosen (for example, 110) in your workflow description or internal runbook so other admins can easily find and update it later. If different fields need different limits, create a separate validator for each with its own threshold.

## How the expression works

- **Null check:** Ensures the field isn't null before counting. If the field is null (unset), the entire expression evaluates to false, so JMWE blocks the transition. If the field should be optional (that is, allow null), change the expression to: `issue.customfield_XXXXX == null || ( ... sum ... ) <= 110`.
- **content.flatMap(...):** Flattens paragraph blocks into a single array of inline nodes.
- **filter(n => n.text != null):** Keeps only nodes with text (skips hard breaks and formatting-only nodes).
- **map(...length):** Converts each text node to its character length.
- **reduce(...):** Sums all lengths and compares against the maximum allowed.

## Optional variants (copy/paste)

<details>
<summary>Allow null/omit field but enforce the limit if provided</summary>

```javascript
issue.customfield_XXXXX == null || (
  issue.customfield_XXXXX.content
    .flatMap(p => p.content)
    .filter(n => n.text != null)
    .map(n => n.text.length)
    .reduce((sum, len) => sum + len, 0)
) <= 110
```
</details>

<details>
<summary>Require non-empty and under the limit</summary>

```javascript
issue.customfield_XXXXX != null && (
  issue.customfield_XXXXX.content
    .flatMap(p => p.content)
    .filter(n => n.text != null)
    .map(n => n.text.length)
    .reduce((sum, len) => sum + len, 0)
) > 0 && (
  issue.customfield_XXXXX.content
    .flatMap(p => p.content)
    .filter(n => n.text != null)
    .map(n => n.text.length)
    .reduce((sum, len) => sum + len, 0)
) <= 110
```
</details>

## Customizing the solution

- Different field: replace customfield_XXXXX with your actual field ID. You can find it by viewing the field's context URL or using the Admin helper tools.
- Different max length: change 110 to any integer limit that fits your policy.
- Whitespace policy: if you want to trim leading/trailing whitespace before counting, convert `n.text.length` to `n.text.trim().length`.

## Common pitfalls and troubleshooting

- Plain length checks fail: Paragraph fields are rich-text objects, not strings. Always traverse the content array as shown.
- Hard breaks count: Line breaks are represented as nodes (for example, hardBreak) without text. The filter step excludes them from counting.
- Empty field handling: If the field object exists but has no text content, the sum equals 0, so JMWE allows the transition. However, if the field is completely null/unset, the null check on line 1 blocks the transition. If the field must be non-empty and under the limit, replace the null check with: `issue.customfield_XXXXX != null && ( ... sum ... ) > 0 && ( ... sum ... ) <= 110`.

## Worked example

Suppose your field is customfield_10181 and your limit is 110 characters. Use this expression:

```javascript
issue.customfield_10181 != null &&
(
  issue.customfield_10181.content
    .flatMap(p => p.content)
    .filter(n => n.text != null)
    .map(n => n.text.length)
    .reduce((sum, len) => sum + len, 0)
) <= 110
```

## Error message suggestion

"Your response exceeds the maximum allowed length of 110 characters for this field. Please shorten your text."

## FAQ

<details>
<summary>Can I count only visible characters and ignore formatting or mentions?</summary>

Yes. The expression already ignores non-text nodes (like hard breaks). If your field can include rich content (for example, emojis or special nodes), the filter step keeps only nodes with a text property.
</details>

<details>
<summary>How do I find my field ID (customfield_XXXXX)?</summary>

- Open Jira Administration > Issues > Custom fields, click the three dots > Contexts and default value; the URL typically contains the ID.
- Use the Admin helper or REST API (GET /rest/api/3/field) if you prefer programmatic lookup.
</details>

## References

- [https://appfire.atlassian.net/wiki/spaces/MWECS/pages/449315100](https://appfire.atlassian.net/wiki/spaces/MWECS/pages/449315100) (JMWE documentation)
- [https://appfire.atlassian.net/wiki/spaces/SUPPORT/pages/1557430297](https://appfire.atlassian.net/wiki/spaces/SUPPORT/pages/1557430297) (related KB article)
- [https://appfire.atlassian.net/servicedesk/customer/portal/11/article/2684420620](https://appfire.atlassian.net/servicedesk/customer/portal/11/article/2684420620)