Skip to content

Fix crash with crossref div and conditional visibility#13995

Open
cderv wants to merge 3 commits intomainfrom
fix/issue-13992
Open

Fix crash with crossref div and conditional visibility#13995
cderv wants to merge 3 commits intomainfrom
fix/issue-13992

Conversation

@cderv
Copy link
Collaborator

@cderv cderv commented Feb 4, 2026

So I have looked into #13995 with the help of Claude Code, and tested different scenarios. I believe this could fix #13992


Summary

Rendering fails with attempt to index a nil value when a div has both:

  • A cross-reference ID (#tbl-, #fig-, #lst-)
  • Conditional visibility class (.content-visible / .content-hidden)

Root Cause

The content-hidden.lua render function assumes node.node is always a Div and calls el.content. However, parsefiguredivs.lua transforms crossref divs into FloatRefTarget custom nodes, which then render to Table/Figure/etc. When the slot content is no longer a Div, calling .content crashes.

Fix

Check if the slot is still a regular Div before accessing .content. For transformed elements, return them wrapped in pandoc.Blocks().

if is_regular_node(el, "Div") then
  clearHiddenVisibleAttributes(el)
  return el.content
else
  return pandoc.Blocks({el})
end

Test Coverage

Added 8 test files covering various scenarios:

  • Table, Figure, Listing (FloatRefTarget transformations)
  • Plain div baseline (no transformation)
  • Nested callout and tabset content

Fixes #13992

cderv and others added 2 commits February 4, 2026 15:55
When a div has both a cross-reference ID (e.g., #tbl-) and conditional
visibility class (.content-visible), the slot content gets transformed
by parsefiguredivs from Div to FloatRefTarget to Table. The render
function in content-hidden.lua assumed the slot was always a Div and
crashed when calling el.content on a Table.

The fix checks if the rendered slot is still a Div before accessing
.content. For transformed elements (Table, etc.), return the element
wrapped in pandoc.Blocks.

Fixes #13992

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests for conditional visibility with various custom nodes that were
affected by the fix in content-hidden.lua:
- Figure (FloatRefTarget)
- Listing (FloatRefTarget)
- Theorem (Theorem custom node)
- Proof (Proof custom node)
- Plain div (baseline)
- Nested callout (Callout custom node)
- Nested tabset (HTML-specific)
- Rename table test to reflect its focus on Table (Table custom node)

Each test verifies PDF, HTML, and Typst output with structure checks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@posit-snyk-bot
Copy link
Collaborator

posit-snyk-bot commented Feb 4, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Document that the clearHiddenVisibleAttributes() call in ConditionalBlock
render is defensive (typically a no-op) since parse() already strips
visibility attrs. Kept as safety net for potential future code changes.
@cderv
Copy link
Collaborator Author

cderv commented Feb 5, 2026

Note on clearHiddenVisibleAttributes() call:

Investigation using AST tracing revealed that this cleanup call is technically a no-op for Divs inside ConditionalBlocks:

  1. The parse function (lines 46-47) strips visibility classes and attrs from the Div before storing it in the slot
  2. By the time render runs, the Div already has empty classes/attrs
  3. Verified via QUARTO_TRACE_FILTERS - Stage 19 shows inner Div with ["", [], []]

We're keeping the call as defensive programming with an explanatory comment, in case future code changes introduce attrs between parse and render. The cost is zero (no-op), but provides a safety net.

This cleanup IS still necessary for Spans/CodeBlocks handled by handleHiddenVisible(), as those don't go through the custom node parse phase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Render to PDF fails with conditionally-visible Markdown table in div with ID

2 participants