Skip to content

breaking: remove special ENOENT support#1861

Merged
fengmk2 merged 1 commit intomasterfrom
remove-ENOENT-support
Mar 19, 2025
Merged

breaking: remove special ENOENT support#1861
fengmk2 merged 1 commit intomasterfrom
remove-ENOENT-support

Conversation

@jonathanong
Copy link
Member

@jonathanong jonathanong commented Mar 18, 2025

This is a huge breaking change as it breaks fs.createReadStream support. Instead, you'll have to make sure you'll handle the stream's errors before it reaches the koa response logic. This is good as you'd want to do this for all streams anyways. You can have an upstream middleware like:

app.use(async (ctx, next) {
  await next()

  // check if the object is a stream
  if (ctx.body?.readable && typeof ctx.body?.pipe === 'function') {
    await new Promise((resolve, reject) => { // wait for it to be either readable or throw an error
      ctx.body.on('readable', () => resolve())
      ctx.body.on('error', (err) => reject(err)) // TODO handle errors
    })
  }
})

closes #1420

@fengmk2 fengmk2 merged commit 9ce4536 into master Mar 19, 2025
7 checks passed
@fengmk2 fengmk2 deleted the remove-ENOENT-support branch March 19, 2025 01:31
@BryceMehring
Copy link

Does https://github.com/koajs/send need to be updated with the new logic?

@Haocen
Copy link

Haocen commented Oct 1, 2025

This is a huge breaking change as it breaks fs.createReadStream support. Instead, you'll have to make sure you'll handle the stream's errors before it reaches the koa response logic. This is good as you'd want to do this for all streams anyways. You can have an upstream middleware like:

app.use(async (ctx, next) {
  await next()

  // check if the object is a stream
  if (ctx.body?.readable && typeof ctx.body?.pipe === 'function') {
    await new Promise((resolve, reject) => { // wait for it to be either readable or throw an error
      ctx.body.on('readable', () => resolve())
      ctx.body.on('error', (err) => reject(err)) // TODO handle errors
    })
  }
})

closes #1420

I don't know why the middleware is not working for me however hard I try(I noticed there is a syntax error, nevertheless), I read through the source code and implemented an alternative.

# Can an AI know that it doesn't know

const isRootCauseErrorENOENT = (err) => {
  if (err instanceof Error) {
    let rootCauseErr = err;
    while (rootCauseErr.cause instanceof Error) {
      rootCauseErr = rootCauseErr.cause;
    }
    return rootCauseErr.code === 'ENOENT';
  }
  return false;
};

app.on('error', (err, ctx) => {
  if (isRootCauseErrorENOENT(err)) {
    // After breaking change introduced in koajs@3.0.0 https://github.com/koajs/koa/pull/1861
    err.status = 404;
  } else {
    console.error('Server error.', err, ctx);
  }
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

koa shouldn't special-case ENOENT errors

4 participants