Fix quarto.version crash on build-metadata version strings - #14894
Merged
Merged
Conversation
….version()
init.lua's version() silently returned the raw version string whenever
pandoc.types.Version() failed to parse it, making quarto.version and
quarto.config.version() polymorphic: a Version object on success, a plain
string otherwise. pandoc.types.Version's dotted-integer parser rejects any
string with a "+" (semver build metadata) or without a leading digit, which
consumers like the `{{< version >}}` shortcode (version.lua) don't expect --
it unconditionally calls table.concat(quarto.version, '.'), which crashes
with "bad argument #1 to 'concat' (table expected, got string)" whenever the
string fallback is hit.
This is reachable outside of CI too: QUARTO_FORCE_VERSION is a user-settable
env override, and quarto-bld prepare-dist --set-version accepts an arbitrary
string, so a distro packager appending a revision suffix could hit the same
crash on a real build.
Extract the leading dot-separated numeric component of the version string
before constructing the Version object, so parsing always succeeds and the
string-fallback branch becomes unreachable. Both quarto.version and
quarto.config.version() go through the same local version() function, so
one fix covers both call sites.
The previous fix extracted the leading numeric prefix from a version string with a fixed-arity pattern chain (^%d+%.%d+%.%d+, then ^%d+%.%d+, then ^%d+), which silently truncates any version with more than three dot-separated numeric components -- e.g. "1.2.3.4" became "1.2.3". QUARTO_FORCE_VERSION and quarto-bld prepare-dist --set-version both accept arbitrary strings, so a 4+ component version is reachable, not just hypothetical. Replace the pattern chain with leadingDottedNumber(), which walks the string collecting all leading dot-separated digit runs instead of matching a hard-coded number of them. Strengthen the existing regression tests to assert the exact concatenated value (not just that table.concat didn't crash), and add a four-component case.
Quarto's own --data-dir resourcePath("pandoc/datadir") pair was
hardcoded independently in three places (crossref, pandoc render,
and the version-repr test), risking drift if the path ever changes.
Collaborator
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
cderv
added a commit
that referenced
this pull request
Sep 17, 2026
…tcode string guard PR #14894 rewrote init.lua's version() to always return a pandoc.types.Version, normalizing the quarto-version filter param to its leading dotted-numeric component. quarto.version can no longer be a plain string, so the tostring() fallback added to version.lua for that case guards a condition that cannot occur, and main's own quarto-version-repr test asserts table.concat succeeds across plain, four-component, build-metadata, and non-numeric inputs. The +test.<date> build-metadata marker on built test distributions is kept deliberately (D2 in llm-docs/built-version-testing-architecture.md): it lets a built test dist announce itself as a CI trial build in `quarto --version` while keeping quarto-required range comparisons valid, and #14894 already makes the marker invisible to Lua filters, which was the only real problem it used to cause.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context: this is to prepare to #14706
When quarto is built with a version string containing semver build metadata (e.g.
1.9.13+test.20260910, as the built-binary CI test workflow stamps, or as a distro packager appending a revision suffix might produce), rendering any document that readsquarto.versionorquarto.config.version()as a table crashes withbad argument #1 to 'concat' (table expected, got string)-- e.g. the{{< version >}}shortcode (src/resources/extensions/quarto/version/version.lua:3).Root Cause
init.lua'sversion()(backing bothquarto.versionandquarto.config.version()) tries to construct apandoc.types.Versionfrom the raw version string and falls back to returning the plain string when construction fails.pandoc.types.Version's parser only accepts dot-separated non-negative integers -- it rejects build metadata and any string without a leading digit -- so any consumer assuming a table crashes on that fallback.Fix
version()now extracts the leading dot-separated numeric component of the version string before constructing theVersionobject, so construction always succeeds and a plain string is never returned. Falls back toVersion('0')when no leading digit is present. Handles versions with any number of dotted components, not just three.Alternative considered: making
version.lua(or other individual consumers) tolerate both a table and a string. This was rejected since it only patches one call site and leaves the same crash reachable fromquarto.config.version()and any third-party extension readingquarto.version.A
pandocDataDirArgs()helper was extracted insrc/core/resources.tsso the new regression test can invoke pandoc directly against the same--data-dira real render uses.