fastify-static: Sporadic ERR_STREAM_PREMATURE_CLOSE

🐛 Bug Report

Seemingly at random, fastify-static will fail to serve a static file.

  • Refreshing/re-requesting the file usually fixes it
  • Happens for text responses and binary files such as PNGs
  • Happens with or without fastify-compress

Stack trace:

Error: Premature close
    at PassThrough.onclose ([redacted]/node_modules/fastify/node_modules/readable-stream/lib/internal/streams/end-of-stream.js:62:73)
    at PassThrough.emit (events.js:215:7)
    at emitCloseNT ([redacted]/node_modules/fastify-static/node_modules/readable-stream/lib/internal/streams/destroy.js:56:8)
    at processTicksAndRejections (internal/process/task_queues.js:79:21)

Error log in console:

{
  "level": 50,
  "time": 1574780438858,
  "pid": 12747,
  "hostname": "[redacted]",
  "reqId": 12,
  "req": {
    "method": "GET",
    "url": "/sa/Home_qVN1-2b1b950.js",
    "remotePort": 52715
   },
   "res": { "statusCode": 500 },
   "err" :{
     "type": "NodeError",
     "message": "Premature close",
     "stack": "Error: Premature close\n    at PassThrough.onclose ([redacted]/node_modules/fastify/node_modules/readable-stream/lib/internal/streams/end-of-stream.js:62:73)\n    at PassThrough.emit (events.js:215:7)\n    at emitCloseNT ([redacted]/node_modules/fastify-static/node_modules/readable-stream/lib/internal/streams/destroy.js:56:8)\n    at processTicksAndRejections (internal/process/task_queues.js:79:21)",
     "name": "Error",
     "code": "ERR_STREAM_PREMATURE_CLOSE"
    },
  "msg": "Premature close",
  "v": 1
}

To Reproduce

Steps to reproduce the behavior:

  1. Serve some static files with fastify-static
  2. Seemingly randomly, the above will happen for page assets
  3. The file indeed never makes it to the browser

Paste your code here:

import path from 'path'
import serveStatic from 'fastify-static'
import fp from 'fastify-plugin'

function staticAssets (server, opts, next) {
  server.register(serveStatic, {
    root: path.join(__dirname, '../browser'),
    prefix: '/sa/',
    maxAge: 9999999,
    immutable: true,
    dotfiles: 'ignore',
    index: false,
    decorateReply: false
  })

  server.register(serveStatic, {
    root: path.join(__dirname, '../server/magic-urls'),
    maxAge: 24 * 60 * 60, // 1 day
    dotfiles: 'ignore',
    index: false,
    decorateReply: false
  })
  next()
}

export default fp(staticAssets, {
  fastify: '2.10',
  name: '[redacted]-static-assets'
})

This plugin is then registered like so:

import staticAssets from './static-assets'

fastify.register(staticAssets)

Expected behavior

A clear and concise description of what you expected to happen.

Paste the results here:

Your Environment

  • node version: 12.13.0
  • fastify version: 2.10.0
  • os: MacOS Mojave 10.14.6
  • Requesting assets with MacOS Firefox 71, but it doesn’t appear to be doing anything special in its devtools

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 23 (8 by maintainers)

Most upvoted comments

For anyone currently with this issue: I was able to fix it by taking the README’s advice and using a local copy of NGiNX to serve static files instead, proxying to the Fastify server for everything else.

I’m able to reproduce this as advised by playing a big video file in Safari and pausing playback / refreshing the page.

The error message in the logs seems to be a red herring as closing the socket is entirely expected behaviour caused by browsers trying to save bandwidth and stopping unnecessary data transfers.