Illegal absmiddle property generated by certain out-of-the-box macros causes PDF export of page to fail and crashes the PDF sandbox

XMLWordPrintable

    • 4
    • Severity 3 - Minor
    • 61

      Problem

      Certain out of the box macros generate instances of align="absmiddle" within rendered HTML code which, in turn, causes the following message snippet to appear in the application logs along with a crash of the PDF sandbox when exporting the page to PDF:

      • IllegalArgumentException: Unknown align attribute: 'absmiddle error

      This issue occurs when:

      • Using the Code or Panel macro with a web link entered within the macro title.
      • Using the User List macro as is.

      Environment

      This issue occurs in Confluence version > 10.0.03

      Steps to Reproduce

      1. Within a given page, create a Code macro and set the title to any web link (ex. https://www.google.com ) OR create an instance of the User List macro.
      2. Save the page.
      3. Export the page to PDF.

      Expected Results

      The page successfully exports to PDF.

      Actual Results

      With the PDF sandbox enabled and conversion sandbox logging enabled, the PDF export fails with the following stack trace and the PDF sandbox crashes after waiting for the default 180 seconds:

      2026-05-05 07:44:19,302 INFO [sandbox-logger] [impl.util.sandbox.ConversionSandbox] lambda$buildConfig$0 worker0: Caused by: java.lang.IllegalArgumentException: Unknown align attribute: 'absmiddle'  | traceId: 3b682985b4886568
      
      2026-05-05 07:47:17,338 WARN [sandbox-terminator] [impl.util.sandbox.SandboxLocalProcessPool] lambda$startTerminator$0 Request has taken 180170ms exceeds limit 180000ms terminating sandbox

      With the PDF sandbox disabled, the PDF export fails with the following stack trace in the application logs:

      2026-05-11 18:22:07,176 ERROR [http-nio-21010-exec-7 url: /c1010/500page.jsp; user: charlie] [atlassian.confluence.status.SystemErrorInformationLogger] logException Unhandled exception, request unique ID: 9c5ad215-d876-4c28-ba23-f683461f043e
       -- traceId: 669a07fa1bde7ffc
      java.lang.RuntimeException: com.atlassian.confluence.importexport.ImportExportException: Exception while rendering the PDF document /Downloads/myApp/confluence-home/atlassian-confluence-10.1.0/temp/pdfexport-20260511-110526-1822-1/BIN-Bingo-110526-1822-2.pdf
      at com.atlassian.confluence.extra.flyingpdf.impl.ExportPageAsPdfAction.doExecute(ExportPageAsPdfAction.java:70)
      ...
      Caused by: java.lang.IllegalArgumentException: Unknown align attribute: 'absmiddle'
      at org.xhtmlrenderer.simple.extend.StyleBuilder.applyFloatingAlign(StyleBuilder.java:84)
      at org.xhtmlrenderer.simple.extend.XhtmlNamespaceHandler.applyImgStyles(XhtmlNamespaceHandler.java:85)
      at org.xhtmlrenderer.simple.extend.XhtmlNamespaceHandler.getNonCssStyling(XhtmlNamespaceHandler.java:66) 

      Additional Notes

       
      After inserting a Code macro with a title that includes a web link, Confluence will render the link with something like the following in the rendered HTML source code:

      <div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b><span class="nobr"><a href="https://google.com" class="external-link" rel="nofollow">https://google.com<sup><img class="rendericon" src="/c1010/images/icons/linkext7.gif" height="7" width="7" align="absmiddle" alt="" border="0"/></sup></a></span></b></div><div class="codeContent panelContent pdl">  

      For a User List macro, the rendered HMTL source code looks like this:

      <tr>
               <td><img src="/c10210/images/icons/user_16.gif" height="16" width="16" border="0" align="absmiddle"/>
                   <a href="/c10210/display/~charlie">charlie</a> <span class="smalltext">(charlie)</span><br/>
                   <span class="smalltext">charlie@atlassian.com</span>
               </td>
           </tr>

      Confirmed Trigger Scenarios

      All of the following produce the same crash:

      Trigger Macro Icon Generated
      Title contains https:// or http:// code linkext7.gif + align="absmiddle"
      Title contains mailto: code mail_small.gif + align="absmiddle"
      Title contains https://http://, or mailto: panel linkext7.gif + align="absmiddle"

      ✅ Confirmed safe (title parameter does not trigger icon rendering): notewarninginfotipexpanddetails

      ⚠️ Important detection note: The align="absmiddle" attribute is generated at render time only — it does not appear in the XHTML that's used to store page content in the BODYCONTENT table.

      Workaround

      The following workarounds are available for instances involving the Code or Panel macro.  A work around for the User List macro is not available as the rendered code is not driven by the presence of any user entered URL.

      Workaround A — Per Page (no DB access required)

      1. Edit the page → click the macro → open the Title field
      2. Remove the scheme prefix only — leave the rest as-is:
      Before After
      https://www.google.com www.google.com
      contact@example.com contact@example.com
      1. Save → re-export to PDF ✅

      Confirmed working on live Confluence 11.


      Workaround B — Global Fix for All Affected Pages (PostgreSQL 17 Tested — requires DB access — queries will need modification for other DBMSs)

      ⚠️ Take a database backup before running. Test in non-production first.

      Find all affected pages

       -- Step 1a: Locate affected pages
      SELECT c.contentid, c.title, (regexp_matches(bc.body, 'ac:name="title">([^<]*(https?:|mailto:)[^<]*)</ac:parameter>'))[1] as macro_title  FROM bodycontent bc JOIN content c ON bc.contentid = c.contentid  WHERE  bc.body ~ 'ac:name="title">[^<]*(https?:|mailto:)[^<]*</ac:parameter>' AND  c.prevver IS NULL AND  c.contenttype = 'PAGE'  ORDER BY c.title;
      
      -- Step 1b: Get a count of the affected pages
      SELECT count(*)  FROM bodycontent bc JOIN content c ON bc.contentid = c.contentid  WHERE  bc.body ~ 'ac:name="title">[^<]*(https?:|mailto:)[^<]*</ac:parameter>' AND  c.prevver IS NULL AND  c.contenttype = 'PAGE';
      

      Apply the fix

       -- Step 2: Create a helper function
       -- Note: this code replaces http/https/mailto with xyz - this can be modified per discretion
      CREATE OR REPLACE FUNCTION fix_title_schemes(body_text TEXT)
      RETURNS TEXT AS $$
      DECLARE
          result TEXT := body_text;
          title_start INT;
          title_end INT;
          block TEXT;
          fixed_block TEXT;
          search_from INT := 1;
          open_tag TEXT := 'ac:name="title">';
          close_tag TEXT := '</ac:parameter>';
      BEGIN
          LOOP
              title_start := POSITION(open_tag IN SUBSTRING(result FROM search_from)) + search_from - 1;
              EXIT WHEN title_start < search_from;        title_end := POSITION(close_tag IN SUBSTRING(result FROM title_start)) + title_start - 1;
              EXIT WHEN title_end < title_start;        block := SUBSTRING(result FROM title_start + LENGTH(open_tag) FOR title_end - title_start - LENGTH(open_tag));
              fixed_block := REGEXP_REPLACE(block, '(https?|mailto):', 'xyz:', 'g');        result := SUBSTRING(result FROM 1 FOR title_start + LENGTH(open_tag) - 1)
                        || fixed_block
                        || SUBSTRING(result FROM title_end);        search_from := title_end + LENGTH(close_tag);
          END LOOP;    RETURN result;
      END;
      $$ LANGUAGE plpgsql;
      
      -- Step 3: Run the UPDATE using the function
      UPDATE bodycontent
      SET body = fix_title_schemes(body)
      WHERE contentid IN
      ( SELECT bc.contentid FROM bodycontent bc 
       JOIN content c ON bc.contentid = c.contentid 
       WHERE 
       bc.body ~ 'ac:name="title">[^<]*(https?:|mailto:)[^<]*</ac:parameter>' AND 
       c.prevver IS NULL AND 
       c.contenttype = 'PAGE')
      RETURNING contentid;
      
      -- Step 4: Drop the helper function when done
      DROP FUNCTION fix_title_schemes(TEXT);

      Verify zero pages remain

       -- Step 5: Locate affected pages 
      SELECT count(*)  FROM bodycontent bc JOIN content c ON bc.contentid = c.contentid  WHERE  bc.body ~ 'ac:name="title">[^<]*(https?:|mailto:)[^<]*</ac:parameter>' AND  c.prevver IS NULL AND  c.contenttype = 'PAGE';
      

      Should return 0.

      Step 4 — Flush render cache 

      With a restart of Confluence:

      This will automatically clear out the caches referenced under Cache Management.

      No restart needed if either occur:

      • Click on the Admin console cog  > General Configuration > Cache Management
      • Click Flush All.

      OR

      curl -u admin:PASSWORD -X DELETE \ "https://your-confluence/rest/cacheManagement/1.0/cacheEntries" \ -H "X-Atlassian-Token: no-check" 

      Returns HTTP 204. Pages re-render correctly immediately. PDF export works without restart. ✅


      📝 Note on the SELECT query: It will also match expand and details macros with URL titles — these are safe (they don’t render the absmiddle icon) but the UPDATE is harmless on them. We kept the broader query rather than filtering by macro type to ensure any third-party macros that do render titles as links are also caught.


      Notes

              Assignee:
              Jeffery Xie
              Reporter:
              Steve Shaw
              Votes:
              5 Vote for this issue
              Watchers:
              10 Start watching this issue

                Created:
                Updated: