Repository navigation
_brand.yml: typography: fonts: source: file option fails #12267
Copy link
Copy link
Open
Labels
documentationDoc improvements & quarto-webDoc improvements & quarto-webyaml-validationIssues with YAML validation and autocompletion in quartoIssues with YAML validation and autocompletion in quarto
Milestone
Description
Bug description
The source: file option does not work for me as expected when trying to specify a custom font in a brand.yml. It insists the source field's value must be google (but I do use it successfully with source: system, for example).
Steps to reproduce
Copy follwing files to same test directory
_brand.yml
typography:
fonts:
- family: Amplitude-Light
source: file
files: Amplitude-Light.ttf
base: Amplitude-Light
headings: Amplitude-Light_quarto.yml
title: Testmy.qmd
# Foo bar
- Test
- Foo
- BarAmplitude-Light.ttf
(not included here, but could be replaced by other suitable font file)
Compile
quarto render my.qmd --to htmlActual behavior
I am getting the following error. Notice in particular the claim that Field "source" has value file, which must instead be 'google', even though I use source: system with system fonts quite successfully on the same machine.
ERROR: Brand validation failed for /home/me/font_test/_brand.yml.
In file _brand.yml
(line 5, columns 7--12) property name files is invalid
4: source: file
5: files: Amplitude-Light.ttf
~~~~~~
6: base: Amplitude-Light
ℹ The error happened in location typography:fonts:0:files.
In file _brand.yml
(line 4, columns 15--19) Field "source" has value file, which must instead be 'google'
3: - family: Amplitude-Light
4: source: file
~~~~~
5: files: Amplitude-Light.ttf
Stack trace:
In file _brand.yml
(line 5, columns 7--12) property name files is invalid
4: source: file
5: files: Amplitude-Light.ttf
~~~~~~
6: base: Amplitude-Light
ℹ The error happened in location typography:fonts:0:files.
In file _brand.yml
(line 4, columns 15--19) Field "source" has value file, which must instead be 'google'
3: - family: Amplitude-Light
4: source: file
~~~~~
5: files: Amplitude-Light.ttf
at readAndValidateYamlFromFile (file:///opt/quarto/bin/quarto.js:20482:15)
at eventLoopTick (ext:core/01_core.js:175:7)
at async projectResolveBrand (file:///opt/quarto/bin/quarto.js:40049:27)
at async resolveFormats (file:///opt/quarto/bin/quarto.js:80545:23)
at async renderContexts (file:///opt/quarto/bin/quarto.js:80377:21)
at async renderFileInternal (file:///opt/quarto/bin/quarto.js:85654:20)
at async renderFiles (file:///opt/quarto/bin/quarto.js:85604:17)
at async renderProject (file:///opt/quarto/bin/quarto.js:86020:25)
at async Command.actionHandler (file:///opt/quarto/bin/quarto.js:90654:32)
at async Command.execute (file:///opt/quarto/bin/quarto.js:8111:13)
Expected behavior
Successful compilation with local font file.
Your environment
- IDE: vim & terminal
- OS: Debian
Quarto check output
Quarto 1.6.42
[✓] Checking environment information...
Quarto cache location: /home/flo/.cache/quarto
[✓] Checking versions of quarto binary dependencies...
Pandoc version 3.4.0: OK
Dart Sass version 1.70.0: OK
Deno version 1.46.3: OK
Typst version 0.11.0: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
Version: 1.6.42
Path: /opt/quarto/bin
[✓] Checking tools....................OK
TinyTeX: (not installed)
Chromium: (not installed)
[✓] Checking LaTeX....................OK
Using: Installation From Path
Path: /usr/bin
Version: 2024
[✓] Checking basic markdown render....OK
[✓] Checking Python 3 installation....OK
Version: 3.12.7
Path: /usr/bin/python3
Jupyter: 5.7.2
Kernels: python3
[✓] Checking Jupyter engine render....OK
[✓] Checking R installation...........OK
Version: 4.4.1
Path: /usr/lib/R
LibPaths:
- /usr/local/lib/R/site-library
- /usr/lib/R/site-library
- /usr/lib/R/library
knitr: 1.48
rmarkdown: 2.27
[✓] Checking Knitr engine render......OK
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationDoc improvements & quarto-webDoc improvements & quarto-webyaml-validationIssues with YAML validation and autocompletion in quartoIssues with YAML validation and autocompletion in quarto
Activity
[-]_brand.yml: `typography:` > `fonts:` > `source: file` option fails[/-][+]_brand.yml: `typography: fonts: source: file` option fails[/+][-]_brand.yml: `typography: fonts: source: file` option fails[/-][+]`_brand.yml`: `typography: fonts: source: file` option fails[/+]mcanouil commentedon Mar 11, 2025
What if you use?
https://posit-dev.github.io/brand-yml/brand/typography.html#comprehensive-example-with-font-definitions
Note that Quarto mentions the complete documentation several times and is not exhaustive about brand.yml which has its own documentation.
floholl commentedon Mar 11, 2025
Yes, indeed this did the trick - thanks! Was aware of the brand.yml documentation, actually, but clearly hadn't dug deep enough there.
mcanouil commentedon Mar 11, 2025
Maybe we could add that files expects an array of "path" in Quarto reference page.
docs: add expected schema for brand typography "files" field
mcanouil commentedon Mar 12, 2025
PR is up:
fix: use "`- path: <path>` or `- <path>`"
docs: add expected schema for brand typography "files" field
fix: use "`- path: <path>` or `- <path>`"
cderv commentedon Oct 26, 2026
I looked at this again while reviewing #12268. The misleading
property name files is invaliderror depends on the length of the string passed tofiles.With a short value, the validator gives the expected error:
With a longer one (
Amp.ttfstill works,Amp-L.ttfdoes not), it reportsproperty name files is invalidand thesourcemust be'google'error instead:Same behavior from 1.6.42 to current dev. Among the
anyOfbranches, the validator keeps the one with the best error quality, then the smallest total span:quarto-cli/src/core/lib/yaml-validation/validator.ts
Lines 249 to 267 in 5b23163
Both branches seem to get the same quality here, so the span decides. The
googlebranch errors span 9 characters (files+file), thefilebranch error spans the value. Any value of 9 characters or more loses, which is most real font file names. I think this is where to look when we improve the error selection.docs: Document that brand typography files takes a list (#12268)
cderv commentedon Oct 27, 2026
I looked further into the length-dependent error from my previous comment, and the span tie-break is only the visible part. The real cause is a heuristic that stopped applying to closed objects.
The
anyOfpruning in the validator is supposed to rank "invalid property name" errors as the least helpful ones, so that a branch which accepted all the keys wins over a branch which rejects one:quarto-cli/src/core/lib/yaml-validation/validator.ts
Lines 221 to 224 in 5b23163
This only looks for
propertyNamesin the schema path. When it was added,closed: trueobjects were compiled to apropertyNamesenum, so it covered them. Since #2367 (Quarto 1.2), closed objects are validated with their ownclosedpath:quarto-cli/src/core/lib/yaml-validation/validator.ts
Line 631 in 5b23163
errors.tswas updated forclosedat that time, but not this ranking (nor theisPropertyNamesErrorcheck just above it at L200). So forbrand-font, thegoogle,bunnyandsystembranches reportproperty name files is invalidwith the same weight as thefilebranch reportingfilesmust be an array, and the smallest span decides. Afilesvalue of 9 characters or more loses to thegooglebranch.This is not specific to a string value. A single object also gets the misleading error:
Workaround
filestakes a list, with either plain paths or objects withpath:With
closedadded to both checks, all of these reportField "files" ... must instead be an array of values, and an unknown key next to a validsourcestill reportsproperty name ... is invalid. Existing schema validation tests pass with it. As this changes which error wins for everyanyOfof closed objects, I want to check the impact on other schemas before proposing it.cderv commentedon Oct 27, 2026
I did the impact check from my previous comment, and it changes what I wrote there. The
closedpath not getting the "invalid property name" ranking is not something to restore. It is what fixed #2349.In #2349,
comments: utterances:with an unknowncrossoriginkey reported the whole mapping asmust be 'false'.commentsis ananyOfoffalseand a closed object. Since #2367, the closed error gets the same ranking as thefalsetype error and wins on span, so the same input reportsproperty name crossorigin is invalid. Addingclosedto the two checks brings back the #2349 message everywhere a closed object sits next to a scalar in ananyOf.I validated generated invalid inputs (unknown key, wrong type for a known key, missing required key, key from another branch) against every
anyOfwith a closed object branch in our schemas: 61 places, 1519 inputs. With theclosedchecks, 31 errors get better and 103 get worse. For example, in_quarto.yml:reports today:
and with the change:
Same for
open-graph,twitter-card,page-footer,comments, navbar items, listingfeed, and all brand light/dark values.What separates the two cases is whether the branch accepts the type of the value at all. In this issue, all
brand-fontbranches are objects and the value is an object, so the branch to report is the one with the fewest key problems. In #2349, thefalsebranch does not accept a mapping, so its error should not win over an error from inside the object branch. So I tried a second rule on top of theclosedchecks: an error saying the value itself has the wrong type for a branch ranks below any error from a branch whose type matched (and anullbranch ranks last, otherwise a scalar front matter reportsmust be the null value).Against all 329
anyOfin our schemas, 5683 inputs (the ones above, plus wrong-type values, empty values,!expr,key:valueandkey=valuestrings), this changes 57 errors: 54 better, 3 neutral, none worse by my reading. It fixes the cases of this issue, and the better ones are mostly the same pattern elsewhere: a valid key reported as invalid by another branch (brand logo paths,funding, bookchaptersitems, sidebarauto), or a mapping given tostring | objectreported asmust be a stringinstead of naming the bad key (include-in-header,engines,date).The 3 neutral ones are
brand-fontwithsource: googleandfiles:, which goes fromproperty name files is invalidtosourcemust be'file'. Both readings make sense to me.I also tried
error-importancetags on thebrand-fontbranches only, as suggested in #2190 for case-by-case fixes. It fixes thefilescases but makessource: filewith a missingfilesreportsourcemust be'google', so I did not go further with it.@cscheid this is the risk you raised in #12268 about making other errors worse. Since then
quarto dev-call validate-yaml --jsongives the full errors in JSON, but no test pins which error is reported across schemas. I could turn the inputs I used into such a test, with the expected error for each input, and propose the change with it. Would this be the kind of testing you wanted before touching the selection ?This is possibly rather low problem, considering all the work on q2, and maybe new validation tooling needs to do that better. I don't know much about it (what q2 uses).
I'll leave this here, the list form in the workaround above works and the description from #12268 points to it.