Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streamablefile throws error for range requests on iOS when playing audio file #14873

Open
3 of 15 tasks
sudarsangp opened this issue Mar 28, 2025 · 4 comments
Open
3 of 15 tasks
Labels
needs triage This issue has not been looked into

Comments

@sudarsangp
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

When a range request is made from iOS device I get this error:

/node_modules/@nestjs/platform-express/adapters/express-adapter.js:51
                    body.errorLogger(err);
                         ^
TypeError: body.errorLogger is not a function
    at /node_modules/@nestjs/platform-express/adapters/express-adapter.js:51:26
    at node:internal/util:464:12
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

When trying to debug the code using debugger, found this thrown from express-adapter.js file, the err object is shown here:

"Error [ERR_STREAM_PREMATURE_CLOSE]: Premature close
    at __node_internal_captureLargerStackTrace (node:internal/errors:496:5)
    at new NodeError (node:internal/errors:405:5)
    at onclose (node:internal/streams/end-of-stream:154:30)
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)"

There were cases when the err object was empty and it didn't thrown an error due to this code:

if (err) {
    body.errorLogger(err);
}

I am not able to catch this error using catch everything exception filter

The code which throws the error is here:

@UseFilters(CatchEverythingFilter)
@Get('get-audio')
async getAudio(
    @Request() req,
    @Res({ passthrough: true }) res: ExpressResponse,
  ) {
    const audioFilePath = 'test/hello.mp3'
    let fileToSend;
    const stat = statSync(audioFilePath);
    const fileSize = stat.size;
    const range = req.headers.range;

    if (range) {
      const parts = range.replace(/bytes=/, '').split('-');
      const start = parseInt(parts[0], 10);
      const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;

      if (start >= fileSize) {
        res.status(416).send('Requested range not satisfiable');
        return;
      }

      fileToSend = createReadStream(audioFilePath, { start, end });

      res.status(206);
      res.setHeader('Content-Type', 'audio/mpeg');
      res.setHeader('Content-Length', end - start + 1);
      res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);
      res.setHeader('Accept-Ranges', 'bytes');
    } else {
      fileToSend = createReadStream(audioFilePath);
      res.set({
        'Content-Type': 'audio/mpeg',
      });
    }

    return new StreamableFile(fileToSend);
}

Any suggestions on how to resolve this error?
Is there any workaround at-least to catch the error?

Minimum reproduction code

https://stackblitz.com/edit/nestjs-typescript-starter-adjltria?file=test%2Fapp.e2e-spec.ts

Steps to reproduce

I am not sure if this is the correct way to reproduce though:

  1. npm run test:e2e

Expected behavior

A way for error to be caught and not kill the entire backend server.
The reason being we cannot control how client makes a request.

Package

  • I don't know. Or some 3rd-party package
  • @nestjs/common
  • @nestjs/core
  • @nestjs/microservices
  • @nestjs/platform-express
  • @nestjs/platform-fastify
  • @nestjs/platform-socket.io
  • @nestjs/platform-ws
  • @nestjs/testing
  • @nestjs/websockets
  • Other (see below)

Other package

No response

NestJS version

^10.0.0

Packages versions

"@nestjs/platform-express": "^10.0.0",

Node.js version

v18.17.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

The issue happens when trying to play the audio on iOS.
Additional context here - https://discord.com/channels/695411232856997968/1354845020548763819/1354845020548763819

@sudarsangp sudarsangp added the needs triage This issue has not been looked into label Mar 28, 2025
@micalevisk
Copy link
Member

I didn't manage to reproduce the error in iOS 16 (safari). /get-audio returned the audio just fine.

@micalevisk
Copy link
Member

I am not able to catch this error using catch everything exception filter

I believe that this is just a limitation of StreamableFile utility, not a bug. Feel free to open another issue to request such feature

@sudarsangp
Copy link
Author

I tried similar code on iOS 15.8 on real device and faced the issue.

@kamilmysliwiec
Copy link
Member

@jmcdo29 is there any scenario when body.errorLogger becomes undefined?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs triage This issue has not been looked into
Projects
None yet
Development

No branches or pull requests

3 participants