Repository: honojs/hono (TypeScript)

Issue:
Changing a `HTTPException` response from `try...catch...finally`
### What version of Hono are you using?

4.7.5

### What runtime/platform is your app running on? (with version if possible)

Cloudflare Workers

### What steps can reproduce the bug?

When throwing a `HTTPException` from a `catch` block, changes made in the `finally` block aren't applied to the response.

For example, deleting cookies in a `finally` block

```ts
import { deleteCookie } from 'hono/cookie'
import { HTTPException } from 'hono/http-exception'

app.use(async (c) => {
  try {
    await maybeError()
  } catch (cause) {
    throw new HTTPException(302, {
      cause,
      res: c.redirect('/?error=invalid_request', 302),
    })
  } finally {
    deleteCookie(c, 'foo')
  }
})
```

### What is the expected behavior?

`try...catch...finally` is a handy way to clean up after an exception, eg;

```ts
try {
  // perform
} catch {
  // handle error
} finally {
  // cleanup
}
```

So I'd expect to see a `set-cookie` header included in the redirect response.

### What do you see instead?

The redirect response does not include a `set-cookie` header

### Additional information

From what I understand, this happens because `c.redirect()` has already created a response using headers that were set before `deleteCookie()` was called. A simpler example of the issue is..

```ts
const response = c.redirect()
deleteCookie(c, 'foo')
response.headers.get('set-cookie') // null
```

I'm sure there are other ways of producing the same result, I initially found this a little surprising, so I had to do some digging to understand why it was happening.

I can work around this by either doing the cleanup twice..

```ts
try {
  await maybeError()
  cleanup()
} catch {
  cleanup()
  throw new HTTPException()
}
```
..or rearranging things so I do the cleanup first..
```ts
try {
  cleanup()
  await maybeError()
} catch {
  throw new HTTPException()
}
```

It's just unfortunate the this part of Hono doesn't work will with regular javascript syntax like the `try...catch...finally` statement


Discussion:
@BarryThePenguin Thank you for the report!

This is a bug. I'll create a PR to fix it.



Patch:
diff --git a/src/hono-base.ts b/src/hono-base.ts
index 80d0ab30d..968983997 100644
--- a/src/hono-base.ts
+++ b/src/hono-base.ts
@@ -35,7 +35,8 @@ const notFoundHandler = (c: Context) => {
 
 const errorHandler = (err: Error | HTTPResponseError, c: Context) => {
   if ('getResponse' in err) {
-    return err.getResponse()
+    const res = err.getResponse()
+    return c.newResponse(res.body, res)
   }
   console.error(err)
   return c.text('Internal Server Error', 500)


Test patch:
diff --git a/src/hono.test.ts b/src/hono.test.ts
index 2283999da..e1585f884 100644
--- a/src/hono.test.ts
+++ b/src/hono.test.ts
@@ -1492,6 +1492,27 @@ describe('Error handle', () => {
       expect(await res.text()).toBe('Custom Error')
     })
   })
+
+  describe('HTTPException with finally block', () => {
+    const app = new Hono()
+    app.use(async (c) => {
+      try {
+        throw new Error()
+      } catch (cause) {
+        throw new HTTPException(302, {
+          cause,
+          res: c.redirect('/?error=invalid_request', 302),
+        })
+      } finally {
+        c.header('x-custom', 'custom message')
+      }
+    })
+    it('Should have the custom header', async () => {
+      const res = await app.request('http://localhost/')
+      expect(res.status).toBe(302)
+      expect(res.headers.get('x-custom')).toBe('custom message')
+    })
+  })
 })
 
 describe('Error handling in middleware', () => {
@@ -3626,7 +3647,7 @@ describe('Generics for Bindings and Variables', () => {
 describe('app.basePath() with the internal #clone()', () => {
   const app = new Hono()
     .notFound((c) => {
-      return c.text(`Custom not found`, 404)
+      return c.text('Custom not found', 404)
     })
     .onError((error, c) => {
       return c.text(`Custom error "${error.message}"`, 500)