Problem
Two related errors are appearing in node renderer production logs:
1. FST_ERR_CTP_INVALID_CONTENT_LENGTH
{
"level": "error",
"name": "RORP HTTP",
"msg": "Unhandled Fastify error",
"err": {
"type": "FastifyError",
"message": "Request body size did not match Content-Length",
"code": "FST_ERR_CTP_INVALID_CONTENT_LENGTH",
"statusCode": 400
}
}
2. INVALID NIL or NULL result for rendering
{
"level": "error",
"name": "RORP",
"msg": "INVALID result for prepareResult\n\nJS code for rendering request was:\nnull\n\nEXCEPTION MESSAGE:\nINVALID NIL or NULL result for rendering"
}
Analysis
Error 1 likely causes Error 2: when Fastify detects a Content-Length mismatch, the multipart body parser aborts, so the renderingRequest field is never attached to req.body. This null then propagates to the render pipeline, producing the confusing "INVALID NIL or NULL result" message.
A probable root cause is stale HTTP/2 persistent connections — the Ruby side writes into a connection that the node renderer has already partially closed, resulting in a truncated body that doesn't match the Content-Length header.
Status
We were unable to reproduce this locally, but #3069 addresses a root cause that can produce this exact pair of errors by:
- Adding early validation of
renderingRequest before entering the render pipeline, returning a descriptive 400 instead of the confusing null-render error
- Distinguishing
FST_ERR_CTP_INVALID_CONTENT_LENGTH in the Fastify onError hook with actionable hints
- Adding
keep_alive_timeout to the HTTPX persistent connection to prevent writing into stale HTTP/2 streams
We will merge #3069 and monitor whether the problem is resolved.
Problem
Two related errors are appearing in node renderer production logs:
1.
FST_ERR_CTP_INVALID_CONTENT_LENGTH{ "level": "error", "name": "RORP HTTP", "msg": "Unhandled Fastify error", "err": { "type": "FastifyError", "message": "Request body size did not match Content-Length", "code": "FST_ERR_CTP_INVALID_CONTENT_LENGTH", "statusCode": 400 } }2.
INVALID NIL or NULL result for rendering{ "level": "error", "name": "RORP", "msg": "INVALID result for prepareResult\n\nJS code for rendering request was:\nnull\n\nEXCEPTION MESSAGE:\nINVALID NIL or NULL result for rendering" }Analysis
Error 1 likely causes Error 2: when Fastify detects a Content-Length mismatch, the multipart body parser aborts, so the
renderingRequestfield is never attached toreq.body. This null then propagates to the render pipeline, producing the confusing "INVALID NIL or NULL result" message.A probable root cause is stale HTTP/2 persistent connections — the Ruby side writes into a connection that the node renderer has already partially closed, resulting in a truncated body that doesn't match the Content-Length header.
Status
We were unable to reproduce this locally, but #3069 addresses a root cause that can produce this exact pair of errors by:
renderingRequestbefore entering the render pipeline, returning a descriptive 400 instead of the confusing null-render errorFST_ERR_CTP_INVALID_CONTENT_LENGTHin the FastifyonErrorhook with actionable hintskeep_alive_timeoutto the HTTPX persistent connection to prevent writing into stale HTTP/2 streamsWe will merge #3069 and monitor whether the problem is resolved.