Skip to content

llms-txt: tables with multi-block cells are replaced by a [TABLE] placeholder in .llms.md #14806

Description

@mcanouil

Bug description

With llms-txt: true, the generated .llms.md files replace some tables with the literal text [TABLE]. All the content of the table is lost. The HTML page keeps the table, so only the LLM-facing variant is damaged.

The tables that are lost are the ones whose cells contain more than one block, for example a grid table or a .list-table div with two paragraphs in one cell. Tables with single-paragraph cells are written correctly as GFM pipe tables.

This is visible on the Quarto website. On https://quarto.org/docs/extensions/lua-api.llms.md, line 291 reads:

The constructors below accept the same fields as documented for each node type, with some additional flexibility:

[TABLE]

### JSON Encoding

The sentence "The constructors below" now points at nothing, so the constructor signatures for quarto.Callout(), quarto.Tabset(), and the other custom nodes are unreachable from the .llms.md page. The same page rendered as HTML, https://quarto.org/docs/extensions/lua-api.html, shows the full table.

The problem is not limited to that page. Counting [TABLE] lines in a few published files:

Page [TABLE] count
docs/reference/formats/html.llms.md 18
docs/authoring/tables.llms.md 3
docs/output-formats/html-themes.llms.md 2

Steps to reproduce

_quarto.yml:

project:
  type: website

website:
  title: "Repro"
  llms-txt: true

index.qmd:

---
title: "Repro"
---

+-------------------+------------------------+
| Constructor       | Fields                 |
+===================+========================+
| `quarto.Callout()`| Required: `type`       |
|                   |                        |
|                   | Optional: `title`      |
+-------------------+------------------------+

Then:

quarto render
cat _site/index.llms.md

Actual behavior

# Repro

[TABLE]

_site/index.html contains the complete table.

Expected behavior

_site/index.llms.md keeps the content of the table, in any form a reader can use. For example a grid table:

# Repro

+-----------------------+--------------------+
| Constructor           | Fields             |
+=======================+====================+
| `quarto.Callout()`    | Required: `type`   |
|                       |                    |
|                       | Optional: `title`  |
+-----------------------+--------------------+

Root cause

convertHtmlToLlmsMarkdown() converts the rendered HTML to markdown with pandoc -t gfm-raw_html.

That target format removes every path Pandoc has to write a complex table. The Markdown writer selects a table syntax with an ordered set of guards. gfm enables pipe_tables but not simple_tables, multiline_tables, or grid_tables, so only the pipe-table branches and the HTML fallback can match. The pipe-table branches need hasSimpleCells. The -raw_html modifier disables Ext_raw_html, which removes the HTML fallback. Nothing matches, so the writer takes the final otherwise branch and emits the literal string [TABLE].

hasSimpleCells comes from onlySimpleTableCells, which accepts a cell only when it holds exactly one Plain or one Para with no line break, or nothing at all. A cell with two paragraphs, a list, or a code block fails this test.

The Custom Nodes table in lua-api.qmd is a .list-table whose cells hold two paragraphs, such as Required: type followed by Optional: title, content, .... That is what makes it fail.

The same input confirms the mechanism outside Quarto, with the Pandoc that Quarto ships:

# cell with two paragraphs
pandoc t.html -f html -t gfm-raw_html --wrap=none
# [TABLE]

pandoc t.html -f html -t gfm --wrap=none
# the table, written as raw HTML

gfm cannot be extended out of the problem, because the writer refuses the extension:

pandoc t.html -f html -t gfm+grid_tables-raw_html
# The extension 'grid_tables' is not supported for gfm.

A target format that keeps a non-pipe table syntax does produce the content. markdown-raw_html writes the same input as a grid table.

Your environment

  • IDE: Terminal
  • OS: macOS 26.6.1

Quarto check output

Quarto 99.9.9
[✓] Checking environment information...
      Quarto cache location: /Users/mcanouil/Library/Caches/quarto
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.10.0: OK
      Dart Sass version 1.101.0: OK
      Deno version 2.7.14: OK
      Typst version 0.15.1: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 99.9.9
      commit: d4cb49f1e70fb34e4cdf38edbb2f938c3ce7cc21
      Path: /Users/mcanouil/Projects/quarto-dev/quarto-cli/package/dist/bin

[✓] Checking tools....................OK
      TinyTeX: v2026.07
      Chrome Headless Shell: (not installed)
      VeraPDF: (not installed)

[✓] Checking LaTeX....................OK
      Using: TinyTex
      Path: /Users/mcanouil/Library/TinyTeX/bin/universal-darwin
      Version: 2026

[✓] Checking Chrome Headless....................OK
      Using: Chrome from QUARTO_CHROMIUM
      Path: /Applications/Brave Browser.app/Contents/MacOS/Brave Browser

[✓] Checking basic markdown render....OK

(|) Checking R installation...........ℹ R version 4.6.1 (2026-06-24)
! Config '~/.Rprofile' was loaded!
[✓] Checking R installation...........OK
      Version: 4.6.1
      Path: /Library/Frameworks/R.framework/Versions/4.6/Resources
      LibPaths:
        - /Users/mcanouil/Projects/quarto-dev/quarto-playground/renv/library/macos/R-4.6/aarch64-apple-darwin23
        - /Users/mcanouil/Library/Caches/org.R-project.R/R/renv/sandbox/macos/R-4.6/aarch64-apple-darwin23/46003b10
      knitr: 1.51
      rmarkdown: 2.31

[✓] Checking Knitr engine render......OK

[✓] Checking Python 3 installation....OK
      Version: 3.9.6
      Path: /Library/Developer/CommandLineTools/usr/bin/python3
      Jupyter: (None)

      Jupyter is not available in this Python installation.
      Install with python3 -m pip install jupyter

      There is an unactivated Python environment in .venv. Did you forget to activate it?

[✓] Checking Julia installation...

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingllms-txt

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions