kestra-io/kestra · error · PebbleException

Couldn't parse the request body

Error message

Couldn't parse the request body

What it means

Thrown by 'http' while building the request body entity: after the body writer serializes the object into a byte array, constructing the Apache HC ByteArrayEntity with the given contentType raises an IOException. In practice a malformed contentType MIME string is the usual culprit.

Source

Thrown at core/src/main/java/io/kestra/core/runners/pebble/functions/HttpFunction.java:136

    private Map<String, List<String>> singleValueToListForHeaders(Map<String, Object> m) {
        return m.entrySet().stream()
            .map(e -> Map.entry(e.getKey(), e.getValue() instanceof String valueStr ? List.of(valueStr) : (List<String>) e.getValue()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    private HttpRequest.RequestBody toRequestBody(Map<String, Object> args, PebbleTemplate self, int lineNumber, String contentType) {
        HttpRequest.RequestBody body;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        Class<T> bodyClass = (Class<T>) args.get("body").getClass();
        MessageBodyWriter<T> bodyWriter = defaultMessageBodyHandlerRegistry.findWriter(Argument.of(bodyClass), MediaType.of(contentType)).orElse(FALLBACK_CONTENT_WRITER);
        bodyWriter.writeTo(Argument.of(bodyClass), MediaType.of(contentType), (T) args.get("body"), new SimpleHttpHeaders(), byteArrayOutputStream);
        try {
            body = HttpRequest.RequestBody.from(
                new ByteArrayEntity(byteArrayOutputStream.toByteArray(), ContentType.create(contentType))
            );
        } catch (IOException e) {
            throw new PebbleException(e, "Couldn't parse the request body", lineNumber, self.getName());
        }
        return body;
    }

    private void throwIfMissingArgs(Map<String, Object> args, PebbleTemplate self, int lineNumber) {
        if (!args.containsKey("uri")) {
            throw new PebbleException(null, "The 'http' function expects an argument 'uri'.", lineNumber, self.getName());
        }
    }

    @Override
    public List<String> getArgumentNames() {
        return List.of("uri", "method", "query", "body", "contentType", "headers", "options", "accept");
    }

    @Override
    public Map<String, String> getArgumentDefaults() {
        HashMap<String, String> defaults = new HashMap<>();

View on GitHub (pinned to 823fada927)

Solutions

  1. Use a valid MIME type string for contentType, e.g. 'application/json', 'application/yaml', 'text/plain'.
  2. If contentType is templated, render it separately to confirm it resolves to a real MIME type.
  3. Omit contentType to accept the 'application/json' default.

Example fix

// before
{{ http(uri, method='POST', body=payload, contentType='json') }}
// after
{{ http(uri, method='POST', body=payload, contentType='application/json') }}
Defensive patterns

Strategy: validation

Validate before calling

{% set ct = contentType ?? 'application/json' %}{% if '/' not in ct %}{% set ct = 'application/json' %}{% endif %}{{ http(uri, method='POST', body=payload, contentType=ct) }}

Prevention

When it happens

Trigger: Passing a malformed contentType such as 'application//json', 'json', or an empty string to http together with a body.

Common situations: Typo or missing slash in the contentType, passing a file extension instead of a MIME type, or a templated contentType that rendered to an unexpected value.

Related errors


AI-assisted analysis of kestra-io/kestra@823fada927 (2026-08-14). Data as JSON: /api/errors/07c51cfac2281c76. Report an issue: GitHub.