Skip to main content

Command Palette

Search for a command to run...

Forge: "Unable to emit ready event." in a macro

Updated
•7 min read•View as Markdown
Forge: "Unable to emit ready event." in a macro
M
I started LeanZero because I saw an industry full of process-heavy companies charging enterprise prices for work that could be done faster, leaner, and more honestly. The Atlassian ecosystem shouldn't require a small army and a six-figure budget to get things done right. I hold Atlassian Certified Administration Expert status, with ACP-120, ACP-220, ACP-420 and ACP-520 covering Jira, Confluence, Jira Service Management and cloud organization administration. Those are the platforms I work with on migrations and app projects. My other certifications include PSM I, SSM and AWS Cloud Practitioner. I specialize in Forge app development with an AI-powered agentic workflow I built myself. The rise of AI changed everything for me — building across multiple stacks became possible without needing a dozen specialists. I use these tools daily, not as a talking point, but as the backbone of how I deliver. Cloud migrations are my bread and butter — I've handled projects of all sizes, from small teams to organizations with tens of thousands of users, each with its own tangle of compliance requirements, legacy systems, and tight deadlines. Forge app development is my newfound love, my way of expressing the builder in me. I've worked on many Forge apps and plan to ship a lot more in the coming year. The MCP Doc Processor came from a simple frustration — when I couldn't find anything noteworthy on the market, I built my own. Privacy, security, and functionality are the holy triangle of any software I build. I'm not selling magic pixie dust. I'll tell you honestly what's possible, what's hard, and what you actually need. If you don't need to pay me, I'll tell you that too.

Key takeaways

  • The error is from view.emitReadyEvent() in @forge/bridge 5.10.2 through 5.12.0: the library re-threw any failure of a bridge call that the Confluence host does not support in normal page view.
  • It was harmless. The EXTENSION_READY event that PDF export consumes is emitted before that bridge call in every version of the library, so the export signal had already gone out when the error fired.
  • 5.13.0 (17 February 2026) removed the throw; the current 7.0.0 carries the same silent catch and a comment naming view mode as the reason. Upgrade @forge/bridge; no manifest or app-code change is needed.
  • Neither Atlassian docs page mentions the rejection. The only written explanation is a comment in the shipped source, which is where the answer to a library error usually is.

You have a Forge Custom UI macro in Confluence. To make PDF export faster and more reliable, you set emitsReadyEvent: true on the macro module and call await view.emitReadyEvent() once your data has loaded, exactly as the docs describe. From then on, every normal page view logs this in the browser console:

Uncaught (in promise) Error: Unable to emit ready event.

The developer who put this to the Forge community on 2 February 2026 had done exactly that, to improve PDF export performance, and asked whether a rejection in normal page view was expected, because the docs do not say. The answer is in the shipped source of @forge/bridge.

Where @forge/bridge throws "Unable to emit ready event"

Unpack @forge/bridge@5.12.0 from the registry and open out/view/emitReadyEvent.js. The whole function is short:

const emitReadyEvent = async () => {
    const context = await view_1.view.getContext();
    await events_1.events.emit(EXTENSION_READY, {
        localId: context.localId
    });
    try {
        const success = await callBridge('emitReadyEvent');
        if (success === false) {
            throw new errors_1.BridgeAPIError('Unable to emit ready event.');
        }
    }
    catch (err) {
        throw new errors_1.BridgeAPIError('Unable to emit ready event.');
    }
};

Three things happen in order. The function reads the macro's context. It emits an EXTENSION_READY event through the Forge events API, carrying the macro's local id. And then it makes a second call, callBridge('emitReadyEvent'), and if that call rejects, or resolves to false, it throws a BridgeAPIError with the message you are seeing. The class is a plain extends Error with no name override, which is why the console line says Error: rather than BridgeAPIError:.

The message is thrown from the library's own catch block. Whatever the Confluence host did with that second call in normal page view, the library's reaction was to convert it into an uncaught rejection in your macro.

Why it was harmless

The ordering is the whole story. The EXTENSION_READY event is what Confluence export consumes; Atlassian's own reference for emitReadyEvent says the function "leverages the Forge Events API to emit an EXTENSION_READY event" so that consumers "such as our PDF export service" can detect when a macro is fully loaded. That emit is the second line of the function, and it is outside the try block. By the time the bridge call fails, the export signal has already gone out.

The later source says so in as many words. In 6.2.0 the same file reads:

const emitReadyEvent = async () => {
    // Confluence export relies on events instead of `callBridge`
    const context = await view_1.view.getContext();
    // dispatches event 'forge.bridge.EXTENSION_READY' on product window
    await events_1.events.emit(EXTENSION_READY, {
        localId: context.localId
    });
    // TODO: Consider using the above event for static macros as well for to avoid two calls
    // `callBridge` is used for static macros in XEP to signal that the forgeDoc is ready to be snapshotted
    try {
        await callBridge('emitReadyEvent');
    }
    catch {
        // Silently ignore the error as this app may be calling this method in Confluence view mode where the method is not supported.
    }
};

So the second call exists for a different consumer, static macros being snapshotted, and the host does not support it in Confluence view mode. Your Custom UI macro on a normal page was calling a method the library's own comment says is not supported in view mode, and the older library treated that as an error worth throwing. The Atlassian staff reply on the community thread, on 11 February, said the same thing without the mechanism: you can safely ignore it, it should have no impact on your app, and a fix is coming.

Which @forge/bridge version stopped it: 5.13.0

The fix landed in @forge/bridge@5.13.0, published on 17 February 2026, six days after that reply. The changelog entry is one line, "Remove error message from emitReadyEvent", and the code change is exactly that: the success === false check is gone, the catch block is empty, and the error import is removed. The error string appears in one file in 5.12.0 and in no file in 5.13.0, 6.2.0, 6.3.1 or the current latest, 7.0.0.

The current 7.0.0, published 14 September 2026, is byte-identical to 6.2.0 and 6.3.1 in this file, comments included; the 7.0.0 changes are elsewhere (fetch, the object-store types, the currentVersion removal) and its changelog does not mention emitReadyEvent. So the situation today is stable: the call is still made, the host still may not support it in view mode, and the library swallows the result.

Going the other way, the changelog says the bridge call was added in 5.10.2, on 5 January 2026, "for usage in static macros". That is the version where the error would first have appeared for a macro on a normal page; checked at source, 5.10.1 makes no bridge call at all and 5.10.2 already has the throw, so the window is 5.10.2 through 5.12.0 and that boundary is verified. The developer who reported it did so a day before 5.12.0 was published, so they were on one of those earlier releases.

What to do

Upgrade @forge/bridge to 5.13.0 or later. Nothing else changes: keep emitsReadyEvent: true in the manifest, keep the await view.emitReadyEvent() call after your data loads. The manifest property was never the problem. Its documentation says that it defaults to false and that it tells Confluence the macro "will send a emitReadyEvent when it has completed loading and is ready for export or further processing", and that is still what it does.

If you cannot upgrade yet, wrapping the call in your own try/catch is safe for the reason above: the export event has already been emitted before anything that can throw.

The part that is not in the docs

Neither the view bridge reference nor the macro module page says that emitReadyEvent rejects, throws, or is unsupported in view mode. Searching both pages for those words finds nothing about this function. The only written statement of what actually happens is the comment in the shipped source, added in 5.16.0. That is not unusual for Forge library errors, and it is the reason this site keeps reading the tarball rather than the changelog when a bridge call misbehaves: the package on the registry is the primary source, and it is one npm pack away.

Two things remain unknown from the outside. What the Confluence host returns for that bridge call in page view, a rejection or a false, cannot be observed from the package, only the library's reaction to it. The explanatory comment first ships in 5.16.0, on 27 April 2026, and that release's changelog entry does not mention it. Neither changes the answer: upgrade, and the console goes quiet.