1.4.0 is a minor release with a behavior change for Litestar services. A second bootstrapper sharing an application also now fails loudly instead of corrupting it — see Bug fixes below.
Litestar's LoggingMiddleware no longer logs requests and responses by
default. If your service is on Litestar and you rely on the HTTP Request
/ HTTP Response access log lines it used to emit, they stop appearing after
this upgrade until you opt back in:
LitestarConfig(
service_name="microservice",
litestar_logging_middleware_enabled=True,
)LitestarLoggingInstrument registers Litestar's StructlogPlugin, and
Litestar's own default LoggingMiddlewareConfig logs full request and
response bodies. That meant:
- Any credential posted to the service — a login form's password, an API
key in a JSON body — landed in stdout verbatim. Litestar only obfuscates
the
Authorization/X-API-KEYheaders and thesessioncookie; request and response bodies are never obfuscated. - Every offline Swagger asset served by
swagger_offline_docs=True(swagger-ui-bundle.js,swagger-ui.css, up to ~150 KB) was logged as an ordinary response body on every request. - Every k8s health probe and every Prometheus scrape produced its own log line, unconditionally.
None of this was opt-in — it was a side effect of adding the plugin. Every other bootstrapper (FastAPI, FastStream, FastMCP, Free) adds no request/response logging middleware at all, so this brings Litestar in line with the rest.
With litestar_logging_middleware_enabled=True, access logs are metadata
only:
- Requests:
path,method,content_type,path_params. - Responses:
status_code.
No body, headers, cookies, or query — bodies and headers are where
secrets live, and query strings carry tokens often enough to not be worth the
diagnostic value. Note that path and path_params are still logged, so a
secret embedded in the URL itself (e.g. /reset-password/{token}) is
recorded; keep secrets in the body, never in the path.
The opt-in also excludes infrastructure routes from access logs: the Swagger
docs path, the offline Swagger static assets (when swagger_offline_docs is
on), the health-check path, and the Prometheus metrics path — each matched
whether or not the corresponding instrument is actually active, so a service
that disables health checks but serves its own route at the same path is
still excluded there.
To take full control — including restoring Litestar's original body-logging
defaults — pass your own LoggingMiddlewareConfig via
litestar_logging_middleware_config. It replaces the hardened defaults
above wholesale, with no merging:
from litestar.middleware.logging import LoggingMiddlewareConfig
LitestarConfig(
service_name="microservice",
litestar_logging_middleware_enabled=True,
litestar_logging_middleware_config=LoggingMiddlewareConfig(
request_log_fields=("path", "method", "content_type"),
),
)Supplying litestar_logging_middleware_config while
litestar_logging_middleware_enabled is False is a no-op that emits a
warning — set the flag to actually turn logging on.
- Litestar apps can read request bodies again.
Litestar.from_config()— whichLitestarBootstrapperuses — passes everyAppConfigfield explicitly, so the 10 MBrequest_max_body_sizedefault thatLitestar(...)applies never reached the built app. Every handler taking a request body returned500: 'request_max_body_size' set to 'Empty' on all layersunless the caller set the field themselves. The bootstrapper now fills it when the config leaves it unset; a caller's own value, including an explicitNonefor no limit, is untouched. Reported upstream as litestar#4296. - Structlog output follows a redirected stdout.
_MemoryLoggerFactoryConfig.log_streamboundsys.stdoutonce, at import time, so a process that replacedsys.stdoutafter importinglite_bootstrapbut before bootstrapping kept logging to the stale stream — while the root-logger handler installed at bootstrap followed the new one. The stream is now resolved at bootstrap, so both agree. Affects every bootstrapper. - The
litestarextra's floor moved from>=2.9to>=2.15.AppConfig.request_max_body_size, which the fix above now reads, was only added in litestar 2.13; andlitestar.middleware.ASGIMiddleware, which the OpenTelemetry middleware already subclassed before this release, was only added in litestar 2.15.>=2.9was never actually supported for the OTel path — this just makes the declared floor honest. - A second bootstrapper sharing an application now fails loudly instead of corrupting it.
Constructing two bootstrappers (FastAPI, Litestar, FastStream, or FastMCP) against the same
application already warned at construction time, but
bootstrap()on the second one applied every instrument again anyway. Litestar died with an unrelated-lookingImproperlyConfiguredException: Handler already registered for path '/health' and http method OPTIONS; FastAPI did not fail at all — the app's route count silently grew (e.g. from 6 to 8 for a default config), a shadowed duplicate of the health-check and metrics routes.bootstrap()on the losing bootstrapper now raisesConfigurationErrornaming itself. If your code relied on the FastAPI case appearing to "work", it will now raise. The ownership marker behind this is never cleared, including byteardown()— once an application has been bootstrapped, it stays owned for the life of the process; construct a fresh application rather than reusing one that was already bootstrapped.
planning/changes/2026-08-10.01-litestar-middleware-logging.mdplanning/changes/2026-08-10.02-log-stream-bind-at-bootstrap.mdplanning/changes/2026-08-10.03-litestar-request-max-body-size.mdplanning/changes/2026-08-10.04-double-bootstrap-guard.md