Changelog - 2026-10-11
Error messages fill their placeholders
Enhancement Behavior ChangeIn one line. The response message of an intentional error is ready to show.
typescript
throw getError({
message: { text: 'Only %{available} left of %{variantId}.', code: 'stock.unavailable' },
messageArgs: { available: 2, variantId: 'V1' },
statusCode: 409,
});json
{
"message": "Only 2 left of V1.",
"normalized": {
"text": "Only %{available} left of %{variantId}.",
"code": "stock.unavailable",
"args": { "available": 2, "variantId": "V1" }
}
}Before, message was the raw template. A client that fell back to message for a code it could not translate showed %{available} to the user.
What changed
messageis filled. The error middleware replaces each%{key}withString(args[key])fromnormalized.args.normalized.textkeeps the template. A client that translatescode+argsworks unchanged. Atransformstill changes onlynormalized.text.Error.messageand the log keep the template. An arg value stays in theargsmap, where the log redacts secret-shaped keys.- A missing arg stays as written. Outside production, the middleware logs one warning that names the code and the missing keys. Production stays silent.
- Only an intentional error is filled. A validation, database or unexpected error writes its own text, and that text passes through unchanged.
A route error inside a Worker host goes through the same middleware, so it answers the same body.
Who is affected
- A client that shows
message. It now shows readable text. No change needed. - A client or test that compares
messagewith the catalog template. Comparenormalized.textinstead, or expect the filled text.
Details
The fill runs in the response only. Filling Error.message too would print each value inline in the log line, outside the redacted args map.
Files: packages/kernel/src/base/middlewares/app-error/app-error.middleware.ts, packages/inversion/src/modules/error/message-template.ts
See Read the error response shape for the full response.