karatelabs/karate · error · TemplateProcessingException

karate-markup does not support param lists in th:fragment…

Error message

karate-markup does not support param lists in th:fragment signatures.\n  Found    th:fragment="${value}"\n  Change   th:fragment="name(p1, p2)"   ➜   th:fragment="name"\n  Pass values via th:with at the call site; ...

What it means

karate-markup does not implement parameterized fragment signatures. When a `th:fragment` attribute value contains a parenthesized parameter list (e.g. `th:fragment="card(title, items)"`), KaFragmentProcessor rejects it via TemplateProcessingException carrying FragmentSupport.signatureMessage, which explains the unsupported syntax and the workaround: declare the fragment without parameters and pass values via `th:with` at the call site.

Solutions

  1. Change the declaration from `th:fragment="name(p1, p2)"` to just `th:fragment="name"`.
  2. At the call site, pass the values via `th:with="p1=..., p2=..."` instead of signature arguments.
  3. Inside the fragment, read the values through `context.get('p1', defaultValue)` for optional fragment params.
  4. Search your templates for `th:fragment="` occurrences containing `(` and fix all of them — the error is raised per-fragment on render.

Example fix

// before
<div th:fragment="card(title, body)">...</div>
<div th:replace="~{frag :: card('Hi', 'Text')}"></div>

// after
<div th:fragment="card">...</div>
<div th:replace="~{frag :: card}" th:with="title='Hi', body='Text'"></div>
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast in tests if any fragment declares params
Files.walk(templatesDir)
    .filter(p -> p.toString().endsWith(".html"))
    .forEach(p -> {
        String s = Files.readString(p);
        Matcher m = Pattern.compile("th:fragment=\"([^\"]*\\()[^\"]*\"").matcher(s);
        if (m.find()) throw new IllegalStateException("Param list in th:fragment in " + p);
    });

Try / catch

try {
    render(template);
} catch (TemplateProcessingException e) {
    if (e.getMessage() != null && e.getMessage().contains("param lists")) {
        log.error("Fragment uses unsupported signature: {}", e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Declaring a fragment as `th:fragment="name(p1, p2)"` — i.e. any th:fragment value containing `(` — then rendering a template that includes it.

Common situations: Migrating templates from full Thymeleaf (which supports `th:fragment="name(p1,p2)"` signatures and `th:replace="~{::frag(...)}"` calls) into Karate markup; copying standard Thymeleaf layout examples from tutorials or the Thymeleaf docs.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/markup/KaFragmentProcessor.java:67

 * check.
 */
final class KaFragmentProcessor extends AbstractElementTagProcessor {

    KaFragmentProcessor(TemplateMode templateMode, String dialectPrefix) {
        super(templateMode, dialectPrefix, null, false,
                StandardFragmentTagProcessor.ATTR_NAME, true,
                StandardFragmentTagProcessor.PRECEDENCE);
    }

    @Override
    protected void doProcess(
            ITemplateContext context,
            IProcessableElementTag tag,
            IElementTagStructureHandler structureHandler) {
        AttributeName attributeName = getMatchingAttributeName().getMatchingAttributeName();
        String value = tag.getAttributeValue(attributeName);
        if (value != null && value.indexOf('(') >= 0) {
            throw new TemplateProcessingException(
                    FragmentSupport.signatureMessage(value, null, null));
        }
        // Marker attribute — strip it now that the validation is done.
        structureHandler.removeAttribute(attributeName);
    }

}

View on GitHub (pinned to a22eb90246)