Skip to content

Website og:image and twitter:image use a data URI prefixed with site-url, ignoring website.image #15055

Closed

Description

@mcanouil

I have:

  • searched the issue tracker for similar issues
  • installed the latest version of Quarto CLI
  • formatted my issue following the Bug Reports guide

Bug description

In a website project, Quarto uses the first image on a page for og:image and twitter:image when the page doesn't set image.
If that first image is a data URI, Quarto still picks it, and prefixes it with site-url.
The tag ends up as https://example.com/data:image/png;base64,..., which no social platform can fetch.
The site-wide website.image would have been a valid fallback, but the data URI wins over it.

Authors can hit this without writing an image at all.
When the author block has an orcid, Quarto renders the ORCID badge as a 16 by 16 PNG data URI, and that badge is the first image on the page.

Two steps in the code lead to this.
findPreviewImgEl returns the first image whose src starts with data:, in the same pass that looks for feature, cover and thumbnail file names:

// look for an image with name feature, cover, or thumbnail
const imgs = doc.querySelectorAll("img");
for (let i = 0; i < imgs.length; i++) {
const img = imgs[i] as Element;
const src = getDecodedAttribute(img, "src");
if (
src !== null && (src.startsWith("data:") || kNamedFileRegex.test(src))
) {
return img;
}
}

imageMetadata then treats the value as a relative path and joins it to site-url, because isAbsoluteRef only recognises http:// and https://:

function imageMetadata(
image: string,
baseUrl: string,
source: string,
context: ProjectContext,
) {
if (isAbsoluteRef(image)) {
// We can't resolve any size data, just return the image
return {
href: image,
};
} else if (image.startsWith("/")) {
// This is a project relative path
const imagePath = join(context.dir, image.slice(1));
const size = imageSize(imagePath);
// read the image size
return {
path: image,
href: joinUrl(baseUrl, image),
height: size?.height,
width: size?.width,
};
} else {
// This is an input relative path
const sourceRelative = relative(context.dir, source);
const imageProjectRelative = join(
dirname(sourceRelative),
image,
);
const imagePath = join(context.dir, imageProjectRelative);
const size = imageSize(imagePath);
// resolve the image path into an absolute href
return {
path: imageProjectRelative,
href: joinUrl(baseUrl, imageProjectRelative),
height: size?.height,
width: size?.width,
};
}
}

export function isAbsoluteRef(href: string) {
return /^(?:http|https)\:\/\/.+/.test(href);
}

On main, the render now fails instead.
Since #15050, imageSize checks every path on disk rather than only .png paths, so the data URI is passed to existsSync as a file name.
On macOS, this stops the render with File name too long (os error 63).

Steps to reproduce

_quarto.yml:

project:
  type: website

website:
  title: "OG repro"
  site-url: https://example.com
  image: site.png
  open-graph: true
  twitter-card: true

index.qmd:

---
title: "Home"
author:
  - name: Jane Doe
    orcid: 0000-0002-0000-0000
---

Some text.

other.qmd:

---
title: "Other"
---

Some text.

Add any PNG as site.png at the project root, then run quarto render.

Actual behavior

With 1.9.38, 1.10.18, 1.10.19 and 1.11.6, _site/index.html has:

<meta property="og:image" content="https://example.com/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ...">
<meta name="twitter:image" content="https://example.com/data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ...">

_site/other.html correctly has https://example.com/site.png, with its width and height.

With main at b86f98d, the render fails on index.qmd:

ERROR: File name too long (os error 63): stat '<project>/data:image/png;base64,iVBORw0KGgo...'

Stack trace:
    at Object.statSync (ext:deno_fs/30_fs.js:432:3)
    at existsSync (https://jsr.io/@std/fs/1.0.16/exists.ts:268:23)
    at imageSize (src/core/image.ts:16:9)
    at imageMetadata (src/project/types/website/website-meta.ts:458:18)
    at resolveImageMetadata (src/project/types/website/website-meta.ts:358:21)

Expected behavior

Quarto skips data URIs when it looks for a preview image, because social platforms can't fetch them.
index.html then falls back to website.image, as other.html does.

If a data URI does end up in image, Quarto leaves it as it is: no site-url prefix, and no attempt to read its size from disk.

Your environment

  • IDE: none, command line.
  • OS: macOS 27.0 (Apple Silicon).

Quarto check output

Quarto 1.11.6
[✓] Checking environment information...
      Quarto cache location: /Users/mcanouil/Library/Caches/quarto
      Project: none found (single-file mode)
[✓] 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: 1.11.6
      Path: /private/tmp/claude-501/-Users-mcanouil-Projects-quarto-extensions/93418f4b-eb51-487a-b7a8-d736f6b97ca2/scratchpad/bins/1.11.6/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

ℹ 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/Library/R/arm64/4.6/library
        - /Library/Frameworks/R.framework/Versions/4.6/Resources/library
      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

[✓] Checking Julia installation...

Activity

  1. added
    bugSomething isn't working
    websitesIssues creating websites
    on Oct 14, 2026
  2. added this to the v1.11 milestone on Oct 15, 2026
  3. self-assigned this
    on Oct 15, 2026
  4. added a commit that references this issue on Oct 16, 2026
    902b926
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingwebsitesIssues creating websites

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions