honojs/hono · error · Error

This context has no ExecutionContext

Error message

This context has no ExecutionContext

What it means

Hono's Context.executionCtx getter throws when no ExecutionContext was captured for the current request. Hono stores the ctx argument from fetch(request, env, ctx) in a private field; if the handler chain never received one (non-workers runtimes, direct app.request() calls), the getter has nothing to return and throws.

Source

Thrown at src/context.ts:395

  get event(): FetchEventLike {
    if (this.#executionCtx && 'respondWith' in this.#executionCtx) {
      return this.#executionCtx
    } else {
      throw Error('This context has no FetchEvent')
    }
  }

  /**
   * @see {@link https://hono.dev/docs/api/context#executionctx}
   * The ExecutionContext associated with the current request.
   *
   * @throws Will throw an error if the context does not have an ExecutionContext.
   */
  get executionCtx(): ExecutionContext {
    if (this.#executionCtx) {
      return this.#executionCtx as ExecutionContext
    } else {
      throw Error('This context has no ExecutionContext')
    }
  }

  /**
   * @see {@link https://hono.dev/docs/api/context#res}
   * The Response object for the current request.
   */
  get res(): Response {
    return (this.#res ||= createResponseInstance(null, {
      headers: (this.#preparedHeaders ??= new Headers()),
    }))
  }

  /**
   * Sets the Response object for the current request.
   *
   * @param _res - The Response object to set.
   */

View on GitHub (pinned to e2740d5a1b)

Solutions

  1. Make waitUntil usage conditional: use c.executionCtx only when available, otherwise await the task or fire-and-forget
  2. In tests, pass a stub ExecutionContext as the third argument to app.request(req, env, fakeCtx)
  3. On Cloudflare Workers, ensure the ctx parameter is forwarded to Hono's fetch handler
  4. Consider a helper that wraps task execution with a fallback when executionCtx is missing

Example fix

// before
c.executionCtx.waitUntil(syncAnalytics()) // throws on Node.js

// after
const task = syncAnalytics()
if ('executionCtx' in c && c.executionCtx) {
  // may still throw if absent; prefer explicit runtime check
}
try {
  c.executionCtx.waitUntil(task)
} catch {
  await task
}
Defensive patterns

Strategy: try-catch

Type guard

const hasExecutionContext = (c: Context): boolean => {
  try {
    c.executionCtx
    return true
  } catch {
    return false
  }
}

Try / catch

try {
  c.executionCtx.waitUntil(task)
} catch {
  // No ExecutionContext — run inline or fire-and-forget
  void task.catch(() => {})
}

Prevention

When it happens

Trigger: Calling c.executionCtx.waitUntil(...) (or passThroughOnException) in a handler running under @hono/node-server, denoServe, Bun.serve, AWS Lambda adapters that don't forward an execution context, or in tests invoked via app.request() without the third executionCtx argument.

Common situations: Using waitUntil in code meant to be runtime-agnostic; upgrading/migrating from Wrangler dev to local Node dev where ctx is absent; unit tests calling app.request(path, env) without an ExecutionContext.

Related errors


AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28). Data as JSON: /api/errors/9aab035b8b2e01e1. Report an issue: GitHub.