I have piece of code that works when forge tunnel is on. However it does not work when simply deployed to any environment.
The code is follows:
export async function mergeInboxItem(item: Omit<InboxItemModel, 'id'>, boardId: string) {
try {
console.log(`Merging inbox item - building query for range [${boardId}] and partition [${item.source.type}, ${item.source.id}]`);
const query = await kvs.entity<StoredInboxItem>('inboxitem')
.query()
.index('by-board-per-sourcetype-sourceid', { partition: [item.source.type, item.source.id] })
.where(WhereConditions.equalTo(boardId))
.limit(100)
.getMany();
console.log(`Query, results found ${query.results.length} items`); // here - only when tunnel is used
// ... rest of the function body
} catch (error) {
console.error('Error merging inbox item', error);
}
}
When deployed logs are as follows:
Info
Jan 21, 2026 16:30:08.301
Merging inbox item - building query for range [557058:998396e4-52c2-4a55-8b81-eccfb28925cb:default] and partition [note, b7dff174-1cd4-448b-b643-680f1fff0456]
Environment: Development
Invocation ID: bf34f9f2-b64b-45f6-9056-d1a3189f7514
Trace ID: b9bd1aca98a278c931220620ad19b609-acf296ad9ecadedb
Module: core:function
Function: tmprl-reminder-trigger
Version: 3.70.0
Site: ptrbjkdev.atlassian.net
Atlassian app: Jira
License: ACTIVE
Note that, no “Query, results found” nor “Error merging inbox item” is present, and the rest function body is not performed during a call.
Hi @piotr.bojko, this is a bit strange. I had a quick look at things from our side, and I couldn’t see anything out of the ordinary. The invocation seems to have succeeded. I can see that it might be a couple of calls to KVS, but only attempted to send one log.
Perhaps you could include a hash of your git commit or something similar to ensure the code running in the Forge function is the exact version you expect. If you are still seeing the discrepancy behaviour, can you please raise a support ticket so we can have a closer look?
I’ve deployed several version changing logs. This behavior persists through all. As soon I run tunnel - this works. It is called from scheduled trigger.
Also, no problem with exposing code if that helps, just within the raised issue.
So it seems I’ve discovered a solution for this. I’ve awaited all promises in a scheduled trigger and it magically worked.
The question is why forge does not check against this, enforce this but rely on this? In java-script there is not strict enforcement on awaiting promises in async function - you can await some promises and some not, especially when your are not interested in outcome of the promise.
Hi @piotr.bojko, glad you found the solution. I was under the impression you were already awaiting your promises, given the code snippet you provided, so I didn’t mention it.
The reason it behaves this way is that Forge functions currently run on top of AWS Lambda. With Lambda, the Node.js execution environment is “frozen” once the handler returns; it doesn’t wait for all event loop to be empty. If a subsequent invocation comes along for the same Lambda instance, then the execution environment will be “unfrozen”, and the execution of unfinished promises will continue. We made a note of the side effect in our docs here, although I think we can make it a bit clearer about not leaving any promises unawaited.
You don’t run into issues while tunnelling, since the Node.js runtime isn’t frozen like it is with AWS Lambda, but your handler will likely return a result before the promise is resolved.