Scheduled/Web trigger function invocation fails with wrapper-level TypeError, regardless of module type or function name

Bug: Scheduled/Web trigger function invocation fails with wrapper-level TypeError, regardless of module type or function name

Summary

A named exported function in index.js, referenced correctly by manifest.yml’s handler field, cannot be invoked by the Forge runtime. Every invocation — whether via scheduledTrigger, webtrigger (manually curled), or after renaming the function to match the documentation’s own example — fails identically with:

TypeError: t[w.functionName] is not a function
    at /mnt/wrapper/wrapper_v24_XX.cjs:2:905258
    at g (/mnt/wrapper/wrapper_v24_XX.cjs:2:905264)
    at new Promise (<anonymous>)
    at /mnt/wrapper/wrapper_v24_XX.cjs:2:904992
    at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:63:14)
    at BufferedInvokeProcessor.Q [as handler] (/mnt/wrapper/wrapper_v24_XX.cjs:2:904238)
    at BufferedInvokeProcessor.processInvoke (file:///var/runtime/index.mjs:1099:33)
    at file:///var/runtime/index.mjs:1185:98
    at InvokeStoreSingle.run (file:///var/runtime/index.mjs:83:12)
    at _Runtime.runWithInvokeContext (file:///var/runtime/index.mjs:1198:24)

Note the wrapper filename version changes between invocations (wrapper_v24_5.cjs, wrapper_v24_20.cjs, wrapper_v24_25.cjs, wrapper_v24_35.cjs, wrapper_v24_50.cjs, wrapper_v24_85.cjs, wrapper_v24_100.cjs — all observed across different invocations of the same function).

A different exported function (index.handler, built via resolver.getDefinitions()) in the same file invokes correctly on every call — the app’s primary resolver-based UI functionality (search, export, saved filters, etc.) all work without issue.

Environment

  • App ID: ari:cloud:ecosystem::app/0628f03f-e8d8-4cdc-b5cc-9dedbe26ebd3
  • Environment: development
  • Site: power-exporter-test.atlassian.net (also reproduced on arzenicstech.atlassian.net)
  • Runtime: nodejs24.x, memoryMB: 512, architecture: arm64
  • Forge CLI: updated to latest (13.1.0) partway through investigation — issue predates and persists after this update

Manifest (relevant excerpt, current state after testing)

modules:
  jira:globalPage:
    - key: power-exporter-page
      resource: main
      resolver:
        function: resolver
      title: Power Exporter for Jira
  scheduledTrigger:
    - key: schedule-runner
      function: schedule-function
      interval: hour
  webtrigger:
    - key: schedule-debug-trigger
      function: schedule-function-debug
  function:
    - key: resolver
      handler: index.handler
    - key: schedule-function
      handler: index.trigger
      timeoutSeconds: 300
    - key: schedule-function-debug
      handler: index.trigger

Function (current, after multiple isolation attempts)

export const trigger = async () => {
  try {
    const prevHeartbeat = await storage.get('scheduler-heartbeat');
    await storage.set('scheduler-heartbeat', {
      lastInvokedAt: new Date().toISOString(),
      invocationCount: ((prevHeartbeat && prevHeartbeat.invocationCount) || 0) + 1,
    });
  } catch (e) {
    console.error('scheduleHandler: heartbeat write failed', e.message);
  }
  // ... (schedule-processing logic omitted for brevity, not reached — crash occurs before any app code runs)
  return { statusCode: 204 };
};

Steps to reproduce

  1. Deploy an app with a scheduledTrigger module pointing to a named function export.
  2. Wait for the hourly interval, or add a temporary webtrigger pointing to the same handler and curl it directly.
  3. Both invocation paths produce the identical TypeError: t[w.functionName] is not a function at the wrapper level — the function body never executes (confirmed via a storage-write placed as the literal first line of the function, which never persists).

What we’ve ruled out (each tested independently, with evidence)

Hypothesis Test performed Result
forge install --upgrade never run Ran it, confirmed via forge install list showing “Up-to-date” Ruled out — still crashes
Stale deployment (old bundle without this function) Fresh forge deploy (full verbose log showing “Upsert scheduled triggers → DONE”), re-tested after Ruled out — crashes on freshly deployed code
Manifest handler string doesn’t match export name Direct line-by-line comparison, index.scheduleHandlerexport const scheduleHandler Ruled out — exact match confirmed
Function-declaration vs arrow-function-const export style Compared against a sibling app (same Atlassian account) using export const automationHandler = async () => {...}, which works correctly; switched to match exactly Ruled out — no change in behavior
Missing required response shape ({statusCode}) Added return { statusCode: 204 } per scheduled trigger events docs Ruled out — crash occurs before this line is ever reached
scheduledTrigger module itself is the faulty invocation path Added a temporary webtrigger pointing to the exact same function, invoked directly via curl Ruled out — identical crash via a completely different invocation mechanism
Bundler/tree-shaking stripping an export with no in-file callers Added an explicit resolver.define() call referencing the function, forcing an in-file usage Ruled out — identical crash persists
Function name itself (scheduleHandler) causing some obscure collision Renamed to trigger, matching the documentation’s own example exactly, in both manifest and export Ruled out — identical crash persists

What still works, for contrast

The resolver.getDefinitions()-based handler export in the same file, wired via jira:globalPage’s resolver, works on every invocation — all app UI functionality (search, export, save filter, etc.) functions correctly. This isolates the issue specifically to functions invoked via scheduledTrigger/webtrigger handler strings pointing directly at a named export, as opposed to functions invoked via the resolver bridge.

Question for the Forge team

Given the above, this appears to be either:

  1. A build/bundling issue specific to how scheduledTrigger/webtrigger handler functions are packaged for this app (vs. resolver-based functions), possibly related to the nodejs24.x runtime or the wrapper version itself (note the wrapper file changes version on almost every invocation — wrapper_v24_5 through wrapper_v24_100 observed), or
  2. Some other platform-side issue with how this specific app’s function module definitions are being resolved at invocation time.

Could someone from the Forge platform team help identify what t and w.functionName refer to in the wrapper’s invocation code, so we can determine why the named export isn’t being found at runtime despite being correctly declared in the manifest and correctly exported in the source?

Happy to provide the full index.js, manifest.yml, or any additional logs needed.

Hi Vikas,

Thank you for a detailed issue report! Can you please paste the full (sanitised if you want) index.js source file with both the non-working export and getDefinitions? This is core Forge functionality and we have multiple automated test suites for this, so there must be something particular going on.