Include macro fails with “Cannot cast java.lang.String to com.atlassian.confluence.xhtml.api.Link” after startup when a JMX monitoring agent reads Confluence MBeans during startup

XMLWordPrintable

    • 1
    • Severity 3 - Minor
    • CtB - Improve Existing

      Issue Summary

      When a Confluence node starts while a JMX monitoring agent is reading its MBeans, Include macros can fail on that node until the Plugins macro metadata cache is flushed. JMX Prometheus exporter (jmx_prometheus_javaagent) is one such agent. Rendering fails with:

      java.lang.ClassCastException: Cannot cast java.lang.String to com.atlassian.confluence.xhtml.api.Link
          at com.atlassian.confluence.xhtml.api.MacroDefinition.getTypedParameter(MacroDefinition.java:184)
          at com.atlassian.confluence.plugins.macros.advanced.IncludeMacroUtils.getLinkOptionalFromMacro(IncludeMacroUtils.java:23)
          at com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro.execute(PageIncludeMacro.java:91)

      During startup, the following is logged:

       

      WARN [AtlassianEvent::CustomizableThreadFactory-N] [impl.macro.metadata.AllMacroMetadataCache] lambda$loadMacroMetadata$1
        Failed to make metadata for module 'confluence.macros.advanced:xhtml-include': ...
        Caused by: java.lang.IllegalArgumentException: Property com.ctc.wstx.addSpaceAfterEmptyElem is not supported
            at java.xml/com.sun.xml.internal.stream.XMLOutputFactoryImpl.setProperty(...)

      Confluence’s StAX factories are created with XMLOutputFactory.newInstance() and XMLInputFactory.newInstance(). These resolve the implementation through the current thread’s context classloader. When the macro metadata build runs on an event worker thread created by a JMX agent thread (system classloader), the lookup can’t see Woodstox and falls back to the JDK’s implementation. The JDK implementation rejects the Woodstox-specific properties Confluence sets, so the Include macros can’t be constructed, and the incomplete macro metadata is cached.

      Steps to Reproduce

      1. Run Confluence Data Center 9.2 on JDK 17 with 4 CPUs (or -XX:ActiveProcessorCount=4). That gives 2 event worker threads.
      2. Add the JMX Prometheus exporter agent, using a config that exports all MBeans (rules: - pattern: ".*"): 
        -javaagent:/path/jmx_prometheus_javaagent-1.0.1.jar=9404:/path/config.yml
      1. Scrape http://<node>:9404/metrics every 1 s or less, starting before Confluence starts.
      2. Restart Confluence several times. After each startup, search atlassian-confluence.log for Failed to make metadata for module 'confluence.macros.advanced:.
      3. On a startup where the WARN appears, view or export a page whose Include macro goes through a macro-definition update during rendering. Apps that transform macro definitions on view do this.

      Expected Results

      Macro metadata is built correctly whichever thread starts it, and Include macros render normally.

      Actual Results

      • The startup WARN above, for confluence.macros.advanced:xhtml-include and confluence.macros.advanced:include. Third-party macros that use Confluence’s XML factories can fail the same way.
      • Include renders and PDF exports then fail with the ClassCastException on that node until the Plugins macro metadata cache is flushed.

      The failure depends on timing, so it appears only after some restarts. Shorter scrape intervals make it more likely.

      The exception below is thrown in the atlassian-confluence.log file during startup:

      WARN [AtlassianEvent::CustomizableThreadFactory-2] [impl.macro.metadata.AllMacroMetadataCache] lambda$loadMacroMetadata$1 Failed to make metadata for module 'confluence.macros.advanced:xhtml-include': Error creating bean with name 'com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro]: Constructor threw exception; nested exception is java.lang.RuntimeException: Error occurred trying to construct a XML output factory
      org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro': Bean instantiation via constructor failed; ...
      	...
      	at com.atlassian.confluence.impl.macro.metadata.AllMacroMetadataLoader.getMacroBodyType(AllMacroMetadataLoader.java:148)
      	at com.atlassian.confluence.impl.macro.metadata.AllMacroMetadataLoader.makeMetadata(AllMacroMetadataLoader.java:111)
      	...
      	at com.atlassian.confluence.macro.browser.DefaultMacroMetadataManager.onPluginFrameworkStartedEvent(DefaultMacroMetadataManager.java:63)
      	...
      Caused by: java.lang.RuntimeException: Error occurred trying to construct a XML output factory
      	at com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro.<init>(PageIncludeMacro.java:60)
      	...
      Caused by: java.lang.IllegalArgumentException: Property com.ctc.wstx.addSpaceAfterEmptyElemis not supported
      	at java.xml/com.sun.xml.internal.stream.XMLOutputFactoryImpl.setProperty(XMLOutputFactoryImpl.java:157)
      	at com.atlassian.confluence.content.render.xhtml.DelegateXmlOutputFactory.setProperty(DelegateXmlOutputFactory.java:69)
      	at com.atlassian.confluence.content.render.xhtml.ConfluenceXmlOutputFactory.create(ConfluenceXmlOutputFactory.java:35)
      	at com.atlassian.confluence.content.render.xhtml.ConfluenceXmlOutputFactory.createFragmentXmlOutputFactory(ConfluenceXmlOutputFactory.java:44)
      	at com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro.<init>(PageIncludeMacro.java:58)
      	...
      

      Afterwards, every Include render on that node logs this in the atlassian-confluence.log file:

      ERROR [http-nio-8090-exec-5] [xhtml.view.macro.ViewMacroMarshaller] handleMacroExecutionException Error rendering macro: include
       -- url: /spaces/flyingpdf/pdfpageexport.action | action: pdfpageexport
      java.lang.ClassCastException: Cannot cast java.lang.String to com.atlassian.confluence.xhtml.api.Link
      	at java.base/java.lang.Class.cast(Class.java:3892)
      	at com.atlassian.confluence.xhtml.api.MacroDefinition.getTypedParameter(MacroDefinition.java:184)
      	at com.atlassian.confluence.plugins.macros.advanced.IncludeMacroUtils.getLinkOptionalFromMacro(IncludeMacroUtils.java:23)
      	at com.atlassian.confluence.plugins.macros.advanced.IncludeMacroUtils.getLink(IncludeMacroUtils.java:18)
      	at com.atlassian.confluence.plugins.macros.advanced.PageIncludeMacro.execute(PageIncludeMacro.java:91)
      	...
      	at com.atlassian.confluence.content.render.xhtml.view.macro.ViewMacroMarshaller.executeMacro(ViewMacroMarshaller.java:244)
      	...
      

      Workaround

      • Flush only the Plugins macro metadata cache: Administration -> General configuration -> Cache management. Alternatively, disable and re-enable the Include modules of the Confluence Advanced Macros app.
      • In the JMX exporter config, either:
        • set startDelaySeconds to more than the node’s startup time (for example 300), so no MBeans are read during startup, or
        • exclude the MBean with excludeObjectNames: ["Confluence:name=CacheStatistics"].

              Assignee:
              Tam Tran
              Reporter:
              Tam Tran
              Votes:
              1 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated: