karatelabs/karate · error · RuntimeException

ka:dispatch trigger must be non-empty after `@`; got

Error message

ka:dispatch trigger must be non-empty after `@`; got `${attributeValue}`

What it means

After splitting ka:dispatch's 'event @ trigger' value on '@', doProcess validates that the trigger substring after the '@' is non-empty and throws a RuntimeException otherwise. An empty trigger gives an unactionable dispatch binding, so the library fails fast with the offending attribute value in the message.

Solutions

  1. Provide a non-empty trigger name after the '@', e.g. ka:dispatch="save @ form-submit"
  2. If a dynamic trigger, ensure the interpolated value is populated at render time
  3. If no trigger is needed, remove the '@' and write just the event name

Example fix

<!-- before -->
<button ka:dispatch="save @"></button>
<!-- after -->
<button ka:dispatch="save @ form-submit"></button>
Defensive patterns

Strategy: validation

Validate before calling

String[] parts = attrValue.split("@", -1); if (parts.length == 2 && parts[1].trim().isEmpty()) throw new IllegalArgumentException("empty ka:dispatch trigger: " + attrValue);

Try / catch

try { render(template, model); } catch (RuntimeException e) { if (e.getMessage() != null && e.getMessage().contains("trigger must be non-empty")) { log.error("bad ka:dispatch: {}", e.getMessage()); } throw e; }

Prevention

When it happens

Trigger: Writing ka:dispatch="eventName @" or "eventName @ " (only whitespace after '@'), often from an incomplete edit or a templated value that rendered empty.

Common situations: Deleting the trigger name while refactoring; interpolating a variable into the attribute that resolved to empty string; copy-paste truncation.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/0529321158165d60. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/markup/KaDispatchProcessor.java:97

        // Split `<dispatched-event> @ <trigger-event>`. The `@`
        // delimiter is optional; without it the dispatch fires on click
        // (default, no htmx dependency). With it, the LHS is the CustomEvent
        // name and the RHS is the DOM/htmx trigger emitted via
        // `hx-on:<trigger>` (htmx must be loaded on the page).
        String av = attributeValue.trim();
        String eventName = av;
        String triggerOn = null;
        int at = av.indexOf('@');
        if (at >= 0) {
            if (av.lastIndexOf('@') != at) {
                throw new RuntimeException(
                        "ka:dispatch supports a single `event @ trigger` delimiter; got `"
                                + attributeValue + "`");
            }
            eventName = av.substring(0, at).trim();
            triggerOn = av.substring(at + 1).trim();
            if (triggerOn.isEmpty()) {
                throw new RuntimeException(
                        "ka:dispatch trigger must be non-empty after `@`; got `"
                                + attributeValue + "`");
            }
        }
        if (eventName.isEmpty()) {
            throw new RuntimeException(
                    "ka:dispatch requires an event name; got `"
                            + attributeValue + "`");
        }
        MarkupTemplateContext kec = (MarkupTemplateContext) ctx;
        String detailJson = "{}";
        String vals = tag.getAttributeValue(getDialectPrefix(), VALS);
        if (vals != null && !vals.isEmpty()) {
            Object result = kec.evalLocalAsObject(vals);
            if (result instanceof Map) {
                detailJson = Json.of(result).toString();
            } else if (result != null) {
                logger.warn("ka:dispatch ignored ka:vals — did not evaluate to an object: {}", vals);

View on GitHub (pinned to a22eb90246)