Skip to content

Micronaut 5 regression: oversized multipart upload can hang a webserver connection instead of returning 413 #19549

Description

@loicmathieu

Summary

A Micronaut 5 regression can hang a connection to Kestra's own webserver when a client uploads a file/multipart body larger than the configured size limit, instead of the server returning a fast 413.

Background

While migrating to Micronaut 5 (#18138), we found that RequestTest.multipartInlineContent_doesNotThrowContentTooLong() — a test that has run reliably in our CI on Micronaut 4 since March 2026 — now hangs instead of observing a clean 413 or connection reset.

Root cause, confirmed via a live thread dump during the hang: Micronaut's Netty server, on deciding an incoming body exceeds the configured size limit, stops reading/draining the socket but does not close or reset the connection. The client is then left blocked forever inside a plain blocking socket write.

This is a regression of an already-fixed Micronaut bug (micronaut-core#4864, fixed in 2022 via PR #6696). That fix lived in io.micronaut.http.netty.stream.HttpStreamsHandler, a class/package that no longer exists in Micronaut 5 — it was replaced by a new streaming-body implementation (StreamingNettyByteBody) as part of Micronaut 5's body-handling rewrite, and the drain-on-reject behavior doesn't appear to have been carried forward.

Filed upstream: micronaut-core#13243.

Why this matters for Kestra specifically

cli/src/main/resources/application.yml sets:

micronaut:
  server:
    max-request-size: 10GB
    multipart:
      max-file-size: 10GB

Any client — browser, Terraform provider, SDK, CI pipeline — uploading a file larger than 10GB to any of Kestra's multipart endpoints (namespace files, flow YAML/ZIP import, FILE-type execution inputs, secrets, KV values) hits this exact rejection path. Concretely:

  • The uploading client hangs indefinitely instead of getting a fast 413.
  • Kestra's server is left holding an idle, un-closed connection per stuck upload. Most affected endpoints require authentication, which limits who can trigger this, but it's not zero-risk as a resource-exhaustion vector if triggered repeatedly.

Test status

RequestTest.multipartInlineContent_doesNotThrowContentTooLong() is @Disabled (not just tagged flaky, since the failure mode is a multi-minute hang rather than a quick intermittent failure) with a reference to both this issue and micronaut-core#13243. Re-enable once the upstream fix lands and is picked up.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/backendNeeds backend code changes

Type

Fields

Stage

In progress

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions