quasarframework/quasar · error · TypeError

Invalid SSR nonce. Expected a non-empty base64 or base64url

Error message

Invalid SSR nonce. Expected a non-empty base64 or base64url value.

What it means

injectNonceAttr copies a CSP nonce into the SSR render context so rendered tags get a nonce attribute. It throws a TypeError when the provided nonce is not a non-empty string matching the base64/base64url pattern (nonceRE), because a malformed nonce would produce an invalid Content-Security-Policy header or enable markup injection.

Source

Thrown at app-vite/templates/entry/ssr-nonce.js:19

const nonceRE = /^[A-Za-z0-9+/_-]+={0,2}$/
const htmlCharsRE = /[&<>"']/g
const encodeHtmlChars = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;'
}

export function injectNonceAttr(ssrContext) {
  const { nonce } = ssrContext
  if (!nonce) {
    ssrContext.__quasarNonceAttr = ''
    return
  }

  if (typeof nonce !== 'string' || !nonceRE.test(nonce)) {
    throw new TypeError(
      'Invalid SSR nonce. Expected a non-empty base64 or base64url value.'
    )
  }

  const value = nonce.replaceAll(htmlCharsRE, char => encodeHtmlChars[char])
  ssrContext.__quasarNonceAttr = ` nonce="${value}"`
}

View on GitHub (pinned to 4841521b5f)

Solutions

  1. Generate the nonce with crypto.randomBytes(16).toString('base64') (or 'base64url')
  2. Verify the value reaches the app non-empty (log it in dev) — empty nonces are allowed (no attribute) but whitespace/junk is not
  3. Strip quotes/whitespace and any surrounding markup from upstream-provided nonces
  4. Do not pre-HTML-escape the nonce; the helper escapes HTML characters itself

Example fix

// before
const nonce = crypto.randomBytes(16).toString('hex') // invalid: hex not base64
// after
const nonce = crypto.randomBytes(16).toString('base64')
Defensive patterns

Strategy: type-guard

Validate before calling

const nonceRE = /^[A-Za-z0-9+/_-]+={0,2}$/
function isValidNonce(nonce) {
  return typeof nonce === 'string' && nonceRE.test(nonce)
}
if (nonce != null && !isValidNonce(nonce)) throw new TypeError('nonce must be base64/base64url')

Type guard

function isValidNonce(v) {
  return typeof v === 'string' && /^[A-Za-z0-9+/_-]+={0,2}$/.test(v)
}

Try / catch

try {
  await ssrRender({ nonce })
} catch (err) {
  if (err instanceof TypeError && err.message.includes('Invalid SSR nonce')) {
    // regenerate the nonce: crypto.randomBytes(16).toString('base64')
  } else throw err
}

Prevention

When it happens

Trigger: Setting an SSR nonce via configuration/env (the value consumed by renderSsrContext, #runVite or renderSsgPage) that is empty, undefined-as-string with wrong chars, contains '<', '"' or other non-base64 characters, or is not a string at all.

Common situations: Generating a nonce with crypto.randomBytes without .toString('base64'/'base64url'); passing a hex-encoded nonce; middleware reading an empty CSP nonce header from upstream; accidentally HTML-escaping the nonce before handing it over.

Related errors


AI-assisted analysis of quasarframework/quasar@4841521b5f (2026-08-30). Data as JSON: /api/errors/3139a65043d652da. Report an issue: GitHub.